Home | History | Annotate | Download | only in util
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 2002-2012, International Business Machines Corporation and    *
      4  * others. All Rights Reserved.                                                *
      5  *******************************************************************************
      6  */
      7 package com.ibm.icu.dev.util;
      8 
      9 import java.util.ArrayList;
     10 import java.util.Arrays;
     11 import java.util.HashSet;
     12 import java.util.Random;
     13 import java.util.Set;
     14 
     15 import com.ibm.icu.text.UTF16;
     16 import com.ibm.icu.text.UnicodeSet;
     17 
     18 abstract public class Pick {
     19     private static boolean DEBUG = false;
     20 
     21     // for using to get strings
     22 
     23     static class Target {
     24         private Pick pick;
     25         private Random random;
     26         private Quoter quoter;
     27 
     28         public static Target make(Pick pick, Random random, Quoter quoter) {
     29             Target result = new Target();
     30             result.pick = pick;
     31             result.random = random;
     32             result.quoter = quoter;
     33             return result;
     34         }
     35         public String next() {
     36             quoter.clear();
     37             pick.addTo(this);
     38             return get();
     39         }
     40         public String get() {
     41             return quoter.toString();
     42         }
     43         private void copyState(Target other) {
     44             random = other.random;
     45         }
     46         private void clear() {
     47             quoter.clear();
     48         }
     49         /*private int length() {
     50             return quoter.length();
     51         }*/
     52         private Target append(int codepoint) {
     53             quoter.append(codepoint);
     54             return this;
     55         }
     56         private Target append(String s) {
     57             quoter.append(s);
     58             return this;
     59         }
     60         // must return value between 0 (inc) and 1 (exc)
     61         private double nextDouble() {
     62             return random.nextDouble();
     63         }
     64     }
     65 
     66     // for Building
     67 
     68     public Pick replace(String toReplace, Pick replacement) {
     69        Replacer visitor = new Replacer(toReplace, replacement);
     70        return visit(visitor);
     71     }
     72 
     73     public Pick name(String nameStr) {
     74         name = nameStr;
     75         return this;
     76     }
     77 
     78     static public Pick.Sequence makeSequence() {
     79         return new Sequence();
     80     }
     81     static public Pick.Alternation makeAlternation() {
     82         return new Alternation();
     83     }
     84     /*
     85     static public Pick.Sequence and(Object item) {
     86         return new Sequence().and2(item);
     87     }
     88     static public Pick.Sequence and(Object[] items) {
     89         return new Sequence().and2(items);
     90     }
     91     static public Pick.Alternation or(int itemWeight, Object item) {
     92         return new Alternation().or2(itemWeight, item);
     93     }
     94     static public Pick.Alternation or(Object[] items) {
     95         return new Alternation().or2(1, items);
     96     }
     97     static public Pick.Alternation or(int itemWeight, Object[] items) {
     98         return new Alternation().or2(itemWeight, items);
     99     }
    100     static public Pick.Alternation or(int[] itemWeights, Object[] items) {
    101         return new Alternation().or2(itemWeights, items);
    102     }
    103 
    104     static public Pick maybe(int percent, Object item) {
    105         return new Repeat(0, 1, new int[]{100-percent, percent}, item);
    106         //return Pick.or(1.0-percent, NOTHING).or2(percent, item);
    107     }
    108     static public Pick repeat(int minCount, int maxCount, int itemWeights, Object item) {
    109         return new Repeat(minCount, maxCount, itemWeights, item);
    110     }
    111 
    112     static public Pick codePoint(String source) {
    113         return new CodePoint(new UnicodeSet(source));
    114     }
    115     */
    116 
    117     static public Pick repeat(int minCount, int maxCount, int[] itemWeights, Pick item) {
    118         return new Repeat(minCount, maxCount, itemWeights, item);
    119     }
    120 
    121     static public Pick codePoint(UnicodeSet source) {
    122         return new CodePoint(source);
    123     }
    124     static public Pick string(String source) {
    125         return new Literal(source);
    126     }
    127     /*
    128     static public Pick unquoted(String source) {
    129         return new Literal(source);
    130     }
    131     static public Pick string(int minLength, int maxLength, Pick item) {
    132         return new Morph(item, minLength, maxLength);
    133     }
    134     */
    135 
    136     public abstract String getInternal(int depth, Set alreadySeen);
    137     // Internals
    138 
    139     protected String name;
    140 
    141     protected abstract void addTo(Target target);
    142     public abstract boolean match(String input, Position p);
    143 
    144     public static class Sequence extends ListPick {
    145         public Sequence and2 (Pick item) {
    146             addInternal(new Pick[] {item}); // we don't care about perf
    147             return this; // for chaining
    148         }
    149         public Sequence and2 (Pick[] itemArray) {
    150             addInternal(itemArray);
    151             return this; // for chaining
    152         }
    153         protected void addTo(Target target) {
    154             for (int i = 0; i < items.length; ++i) {
    155                 items[i].addTo(target);
    156             }
    157         }
    158         public String getInternal(int depth, Set alreadySeen) {
    159             String result = checkName(name, alreadySeen);
    160             if (result.startsWith("$")) return result;
    161             result = indent(depth) + result + "SEQ(";
    162             for (int i = 0; i < items.length; ++i) {
    163                 if (i != 0) result += ", ";
    164                 result += items[i].getInternal(depth+1, alreadySeen);
    165             }
    166             result += ")";
    167             return result;
    168         }
    169         // keep private
    170         private Sequence() {}
    171         public boolean match(String input, Position p) {
    172             int originalIndex = p.index;
    173             for (int i = 0; i < items.length; ++i) {
    174                 if (!items[i].match(input, p)) {
    175                     p.index = originalIndex;
    176                     return false;
    177                 }
    178             }
    179             return true;
    180         }
    181     }
    182 
    183     String checkName(String nameStr, Set alreadySeen) {
    184         if (nameStr == null) return "";
    185         if (alreadySeen.contains(nameStr)) return nameStr;
    186         alreadySeen.add(nameStr);
    187         return "{" + nameStr + "=}";
    188     }
    189 
    190     public static class Alternation extends ListPick {
    191         private WeightedIndex weightedIndex = new WeightedIndex(0);
    192 
    193         public Alternation or2 (Pick[] newItems) {
    194             return or2(1, newItems);
    195         }
    196         public Alternation or2 (int itemWeight, Pick item) {
    197             return or2(itemWeight, new Pick[] {item}); // we don't care about perf
    198         }
    199         public Alternation or2 (int itemWeight, Pick[] newItems) {
    200             int[] itemWeights = new int[newItems.length];
    201             Arrays.fill(itemWeights,itemWeight);
    202             return or2(itemWeights, newItems); // we don't care about perf
    203         }
    204         public Alternation or2 (int[] itemWeights, Pick[] newItems) {
    205             if (newItems.length != itemWeights.length) {
    206                 throw new ArrayIndexOutOfBoundsException(
    207                     "or lengths must be equal: " + newItems.length + " != " + itemWeights.length);
    208             }
    209            // int lastLen = this.items.length;
    210             addInternal(newItems);
    211             weightedIndex.add(itemWeights);
    212             return this; // for chaining
    213         }
    214         protected void addTo(Target target) {
    215             items[weightedIndex.toIndex(target.nextDouble())].addTo(target);
    216         }
    217 
    218         public String getInternal(int depth, Set alreadySeen) {
    219             String result = checkName(name, alreadySeen);
    220             if (result.startsWith("$")) return result;
    221             result = indent(depth) + result + "OR(";
    222             for (int i = 0; i < items.length; ++i) {
    223                 if (i != 0) result += ", ";
    224                 result += items[i].getInternal(depth+1, alreadySeen) + "/" + weightedIndex.weights[i];
    225             }
    226             return result + ")";
    227         }
    228         // keep private
    229         private Alternation() {}
    230         // take first matching option
    231         public boolean match(String input, Position p) {
    232             for (int i = 0; i < weightedIndex.weights.length; ++i) {
    233                 if (p.isFailure(this,i)) continue;
    234                 if (items[i].match(input, p)) return true;
    235                 p.setFailure(this, i);
    236             }
    237             return false;
    238         }
    239     }
    240 
    241     private static String indent(int depth) {
    242         String result = "\r\n";
    243         for (int i = 0; i < depth; ++i) {
    244             result += " ";
    245         }
    246         return result;
    247     }
    248 
    249     private static class Repeat extends ItemPick {
    250         WeightedIndex weightedIndex;
    251         int minCount = 0;
    252 
    253         private Repeat(int minCount, int maxCount, int[] itemWeights, Pick item) {
    254             super(item);
    255             weightedIndex = new WeightedIndex(minCount).add(maxCount-minCount+1, itemWeights);
    256         }
    257         /*private Repeat(int minCount, int maxCount, int itemWeight, Pick item) {
    258             super(item);
    259             weightedIndex = new WeightedIndex(minCount).add(maxCount-minCount+1, itemWeight);
    260         }*/
    261         /*
    262         private Repeat(int minCount, int maxCount, Object item) {
    263             this.item = convert(item);
    264             weightedIndex = new WeightedIndex(minCount).add(maxCount-minCount+1, 1);
    265         }
    266         */
    267         protected void addTo(Target target) {
    268             //int count ;
    269             for (int i = weightedIndex.toIndex(target.nextDouble()); i > 0; --i) {
    270                 item.addTo(target);
    271             }
    272         }
    273         public String getInternal(int depth, Set alreadySeen) {
    274             String result = checkName(name, alreadySeen);
    275             if (result.startsWith("$")) return result;
    276             result = indent(depth) + result + "REPEAT(" + weightedIndex
    277             + "; "+ item.getInternal(depth+1, alreadySeen)
    278             + ")";
    279             return result;
    280         }
    281 
    282         // match longest, e.g. up to just before a failure
    283         public boolean match(String input, Position p) {
    284             //int bestMatch = p.index;
    285             int count = 0;
    286             for (int i = 0; i < weightedIndex.weights.length; ++i) {
    287                 if (p.isFailure(this,i)) break;
    288                 if (!item.match(input, p)) {
    289                     p.setFailure(this,i);
    290                     break;
    291                 }
    292                 //bestMatch = p.index;
    293                 count++;
    294             }
    295             if (count >= minCount) {
    296                 return true;
    297             }
    298             // TODO fix failure
    299             return false;
    300         }
    301     }
    302 
    303     private static class CodePoint extends FinalPick {
    304         private UnicodeSet source;
    305 
    306         private CodePoint(UnicodeSet source) {
    307             this.source = source;
    308         }
    309         protected void addTo(Target target) {
    310             target.append(source.charAt(pick(target.random,0,source.size()-1)));
    311         }
    312         public boolean match(String s, Position p) {
    313             int cp = UTF16.charAt(s, p.index);
    314             if (source.contains(cp)) {
    315                 p.index += UTF16.getCharCount(cp);
    316                 return true;
    317             }
    318             p.setMax("codePoint");
    319             return false;
    320         }
    321         public String getInternal(int depth, Set alreadySeen) {
    322             String result = checkName(name, alreadySeen);
    323             if (result.startsWith("$")) return result;
    324             return source.toString();
    325         }
    326     }
    327 
    328     static class Morph extends ItemPick {
    329         Morph(Pick item) {
    330             super(item);
    331         }
    332 
    333         private String lastValue = null;
    334         private Target addBuffer = Target.make(this, null, new Quoter.RuleQuoter());
    335         private StringBuffer mergeBuffer = new StringBuffer();
    336 
    337         private static final int COPY_NEW = 0, COPY_BOTH = 1, COPY_LAST = 3, SKIP = 4,
    338                                  LEAST_SKIP = 4;
    339         // give weights to the above. make sure we delete about the same as we insert
    340         private static final WeightedIndex choice = new WeightedIndex(0)
    341             .add(new int[] {10, 10, 100, 10});
    342 
    343         protected void addTo(Target target) {
    344             // get contents into separate buffer
    345             addBuffer.copyState(target);
    346             addBuffer.clear();
    347             item.addTo(addBuffer);
    348             String newValue = addBuffer.get();
    349             if (DEBUG) System.out.println("Old: " + lastValue + ", New:" + newValue);
    350 
    351             // if not first one, merge with old
    352             if (lastValue != null) {
    353                 mergeBuffer.setLength(0);
    354                 int lastIndex = 0;
    355                 int newIndex = 0;
    356                 // the new length is a random value between old and new.
    357                 int newLenLimit = (int) pick(target.random, lastValue.length(), newValue.length());
    358 
    359                 while (mergeBuffer.length() < newLenLimit
    360                   && newIndex < newValue.length()
    361                   && lastIndex < lastValue.length()) {
    362                     int c = choice.toIndex(target.nextDouble());
    363                     if (c == COPY_NEW || c == COPY_BOTH || c == SKIP) {
    364                         newIndex = getChar(newValue, newIndex, mergeBuffer, c < LEAST_SKIP);
    365                         if (mergeBuffer.length() >= newLenLimit) break;
    366                     }
    367                     if (c == COPY_LAST || c == COPY_BOTH || c == SKIP) {
    368                         lastIndex = getChar(lastValue, lastIndex, mergeBuffer, c < LEAST_SKIP);
    369                     }
    370                 }
    371                 newValue = mergeBuffer.toString();
    372             }
    373             lastValue = newValue;
    374             target.append(newValue);
    375             if (DEBUG) System.out.println("Result: " + newValue);
    376         }
    377 
    378         public String getInternal(int depth, Set alreadySeen) {
    379             String result = checkName(name, alreadySeen);
    380             if (result.startsWith("$")) return result;
    381             return indent(depth) + result + "MORPH("
    382                 + item.getInternal(depth+1, alreadySeen)
    383                 + ")";
    384         }
    385 
    386         /* (non-Javadoc)
    387          * @see Pick#match(java.lang.String, Pick.Position)
    388          */
    389         public boolean match(String input, Position p) {
    390             // TODO Auto-generated method stub
    391             return false;
    392         }
    393     }
    394 
    395     /* Add character if we can
    396      */
    397     static int getChar(String newValue, int newIndex, StringBuffer mergeBuffer, boolean copy) {
    398         if (newIndex >= newValue.length()) return newIndex;
    399         int cp = UTF16.charAt(newValue,newIndex);
    400         if (copy) UTF16.append(mergeBuffer, cp);
    401         return newIndex + UTF16.getCharCount(cp);
    402     }
    403 
    404     /*
    405             // quoted add
    406             appendQuoted(target, addBuffer.toString(), quoteBuffer);
    407             // fix buffers
    408             StringBuffer swapTemp = addBuffer;
    409             addBuffer = source;
    410             source = swapTemp;
    411         }
    412     }
    413     */
    414 
    415 
    416     static class Quote extends ItemPick {
    417         Quote(Pick item) {
    418             super(item);
    419         }
    420         protected void addTo(Target target) {
    421             target.quoter.setQuoting(true);
    422             item.addTo(target);
    423             target.quoter.setQuoting(false);
    424         }
    425 
    426         public boolean match(String s, Position p) {
    427             return false;
    428         }
    429 
    430         public String getInternal(int depth, Set alreadySeen) {
    431             String result = checkName(name, alreadySeen);
    432             if (result.startsWith("$")) return result;
    433             return indent(depth) + result + "QUOTE(" + item.getInternal(depth+1, alreadySeen)
    434                 + ")";
    435         }
    436     }
    437 
    438     private static class Literal extends FinalPick {
    439         public String toString() {
    440             return name;
    441         }
    442         private Literal(String source) {
    443             this.name = source;
    444         }
    445         protected void addTo(Target target) {
    446             target.append(name);
    447         }
    448         public boolean match(String input, Position p) {
    449             int len = name.length();
    450             if (input.regionMatches(p.index, name, 0, len)) {
    451                 p.index += len;
    452                 return true;
    453             }
    454             p.setMax("literal");
    455             return false;
    456         }
    457         public String getInternal(int depth, Set alreadySeen) {
    458             return "'" + name + "'";
    459         }
    460     }
    461 
    462     public static class Position {
    463         public ArrayList failures = new ArrayList();
    464         public int index;
    465         public int maxInt;
    466         public String maxType;
    467         public void setMax(String type) {
    468             if (index >= maxInt) {
    469                 maxType = type;
    470             }
    471         }
    472         public String toString() {
    473             return "index; " + index
    474                 + ", maxInt:" + maxInt
    475                 + ", maxType: " + maxType;
    476         }
    477         /*private static final Object BAD = new Object();
    478         private static final Object GOOD = new Object();*/
    479 
    480         public boolean isFailure(Pick pick, int item) {
    481             ArrayList val = (ArrayList)failures.get(index);
    482             if (val == null) return false;
    483             Set set = (Set)val.get(item);
    484             if (set == null) return false;
    485             return !set.contains(pick);
    486         }
    487         public void setFailure(Pick pick, int item) {
    488             ArrayList val = (ArrayList)failures.get(index);
    489             if (val == null) {
    490                 val = new ArrayList();
    491                 failures.set(index, val);
    492             }
    493             Set set = (Set)val.get(item);
    494             if (set == null) {
    495                 set = new HashSet();
    496                 val.set(item, set);
    497             }
    498             set.add(pick);
    499         }
    500     }
    501 
    502     /*
    503     public static final Pick NOTHING = new Nothing();
    504 
    505 
    506     private static class Nothing extends FinalPick {
    507         protected void addTo(Target target) {}
    508         protected boolean match(String input, Position p) {
    509             return true;
    510         }
    511         public String getInternal(int depth, Set alreadySeen) {
    512             return indent(depth) + "\u00F8";
    513         }
    514     }
    515     */
    516 
    517     // intermediates
    518 
    519     abstract static class Visitor {
    520         Set already = new HashSet();
    521         // Note: each visitor should return the Pick that will replace a (or a itself)
    522         abstract Pick handle(Pick a);
    523         boolean alreadyEntered(Pick item) {
    524             boolean result = already.contains(item);
    525             already.add(item);
    526             return result;
    527         }
    528         void reset() {
    529             already.clear();
    530         }
    531     }
    532 
    533     protected abstract Pick visit(Visitor visitor);
    534 
    535     static class Replacer extends Visitor {
    536         String toReplace;
    537         Pick replacement;
    538         Replacer(String toReplace, Pick replacement) {
    539             this.toReplace = toReplace;
    540             this.replacement = replacement;
    541         }
    542         public Pick handle(Pick a) {
    543             if (toReplace.equals(a.name)) {
    544                 a = replacement;
    545             }
    546             return a;
    547        }
    548     }
    549 
    550     abstract private static class FinalPick extends Pick {
    551         public Pick visit(Visitor visitor) {
    552             return visitor.handle(this);
    553        }
    554     }
    555 
    556     private abstract static class ItemPick extends Pick {
    557        protected Pick item;
    558 
    559        ItemPick (Pick item) {
    560            this.item = item;
    561        }
    562 
    563        public Pick visit(Visitor visitor) {
    564            Pick result = visitor.handle(this);
    565            if (visitor.alreadyEntered(this)) return result;
    566            if (item != null) item = item.visit(visitor);
    567            return result;
    568        }
    569     }
    570 
    571     private abstract static class ListPick extends Pick {
    572         protected Pick[] items = new Pick[0];
    573 
    574         Pick simplify() {
    575             if (items.length > 1) return this;
    576             if (items.length == 1) return items[0];
    577             return null;
    578         }
    579 
    580         int size() {
    581             return items.length;
    582         }
    583 
    584         Pick getLast() {
    585             return items[items.length-1];
    586         }
    587 
    588         void setLast(Pick newOne) {
    589             items[items.length-1] = newOne;
    590         }
    591 
    592         protected void addInternal(Pick[] objs) {
    593             int lastLen = items.length;
    594             items = realloc(items, items.length + objs.length);
    595             for (int i = 0; i < objs.length; ++i) {
    596                 items[lastLen + i] = objs[i];
    597             }
    598         }
    599 
    600         public Pick visit(Visitor visitor) {
    601             Pick result = visitor.handle(this);
    602             if (visitor.alreadyEntered(this)) return result;
    603             for (int i = 0; i < items.length; ++i) {
    604                 items[i] = items[i].visit(visitor);
    605             }
    606             return result;
    607         }
    608     }
    609 
    610     /**
    611      * Simple class to distribute a number between 0 (inclusive) and 1 (exclusive) among
    612      * a number of indices, where each index is weighted.
    613      * Item weights may be zero, but cannot be negative.
    614      * @author Davis
    615      */
    616     // As in other case, we use an array for runtime speed; don't care about buildspeed.
    617     public static class WeightedIndex {
    618         private int[] weights = new int[0];
    619         private int minCount = 0;
    620         private double total;
    621 
    622         public WeightedIndex(int minCount) {
    623             this.minCount = minCount;
    624         }
    625 
    626         public WeightedIndex add(int count, int itemWeights) {
    627             if (count > 0) {
    628                 int[] newWeights = new int[count];
    629                 if (itemWeights < 1) itemWeights = 1;
    630                 Arrays.fill(newWeights, 0, count, itemWeights);
    631                 add(1, newWeights);
    632             }
    633             return this; // for chaining
    634         }
    635 
    636         public WeightedIndex add(int[] newWeights) {
    637             return add(newWeights.length, newWeights);
    638         }
    639 
    640         public WeightedIndex add(int maxCount, int[] newWeights) {
    641             if (newWeights == null) newWeights = new int[]{1};
    642             int oldLen = weights.length;
    643             if (maxCount < newWeights.length) maxCount = newWeights.length;
    644             weights = (int[]) realloc(weights, weights.length + maxCount);
    645             System.arraycopy(newWeights, 0, weights, oldLen, newWeights.length);
    646             int lastWeight = weights[oldLen + newWeights.length-1];
    647             for (int i = oldLen + newWeights.length; i < maxCount; ++i) {
    648                 weights[i] = lastWeight;
    649             }
    650             total = 0;
    651             for (int i = 0; i < weights.length; ++i) {
    652                 if (weights[i] < 0) {
    653                     throw new RuntimeException("only positive weights: " + i);
    654                 }
    655                 total += weights[i];
    656             }
    657             return this; // for chaining
    658         }
    659 
    660         // TODO, make this more efficient
    661         public int toIndex(double zeroToOne) {
    662             double weight = zeroToOne*total;
    663             int i;
    664             for (i = 0; i < weights.length; ++i) {
    665                 weight -= weights[i];
    666                 if (weight <= 0) break;
    667             }
    668             return i + minCount;
    669         }
    670         public String toString() {
    671             String result = "";
    672             for (int i = 0; i < minCount; ++i) {
    673                 if (result.length() != 0) result += ",";
    674                 result += "0";
    675             }
    676             for (int i = 0; i < weights.length; ++i) {
    677                 if (result.length() != 0) result += ",";
    678                 result += weights[i];
    679             }
    680             return result;
    681         }
    682     }
    683     /*
    684     private static Pick convert(Object obj) {
    685         if (obj instanceof Pick) return (Pick)obj;
    686         return new Literal(obj.toString(), false);
    687     }
    688     */
    689     // Useful statics
    690 
    691     static public int pick(Random random, int start, int end) {
    692         return start + (int)(random.nextDouble() * (end + 1 - start));
    693     }
    694 
    695     static public double pick(Random random, double start, double end) {
    696         return start + (random.nextDouble() * (end + 1 - start));
    697     }
    698 
    699     static public boolean pick(Random random, double percent) {
    700         return random.nextDouble() <= percent;
    701     }
    702 
    703     static public int pick(Random random, UnicodeSet s) {
    704         return s.charAt(pick(random, 0,s.size()-1));
    705     }
    706 
    707     static public String pick(Random random, String[] source) {
    708         return source[pick(random, 0, source.length-1)];
    709     }
    710 
    711     // these utilities really ought to be in Java
    712 
    713 public static double[] realloc(double[] source, int newSize) {
    714     double[] temp = new double[newSize];
    715     if (newSize > source.length) newSize = source.length;
    716     if (newSize != 0) System.arraycopy(source,0,temp,0,newSize);
    717     return temp;
    718 }
    719 
    720 public static int[] realloc(int[] source, int newSize) {
    721     int[] temp = new int[newSize];
    722     if (newSize > source.length) newSize = source.length;
    723     if (newSize != 0) System.arraycopy(source,0,temp,0,newSize);
    724     return temp;
    725 }
    726 
    727     public static Pick[] realloc(Pick[] source, int newSize) {
    728         Pick[] temp = new Pick[newSize];
    729         if (newSize > source.length) newSize = source.length;
    730         if (newSize != 0) System.arraycopy(source,0,temp,0,newSize);
    731         return temp;
    732     }
    733 
    734     // test utilities
    735     /*private static void append(StringBuffer target, String toAdd, StringBuffer quoteBuffer) {
    736         Utility.appendToRule(target, (int)-1, true, false, quoteBuffer); // close previous quote
    737         if (DEBUG) System.out.println("\"" + toAdd + "\"");
    738         target.append(toAdd);
    739     }
    740 
    741     private static void appendQuoted(StringBuffer target, String toAdd, StringBuffer quoteBuffer) {
    742         if (DEBUG) System.out.println("\"" + toAdd + "\"");
    743         Utility.appendToRule(target, toAdd, false, false, quoteBuffer);
    744     }*/
    745 
    746     /*
    747     public static abstract class MatchHandler {
    748         public abstract void handleString(String source, int start, int limit);
    749         public abstract void handleSequence(String source, int start, int limit);
    750         public abstract void handleAlternation(String source, int start, int limit);
    751 
    752     }
    753     */
    754     /*
    755     // redistributes random value
    756     // values are still between 0 and 1, but with a different distribution
    757     public interface Spread {
    758         public double spread(double value);
    759     }
    760 
    761     // give the weight for the high end.
    762     // values are linearly scaled according to the weight.
    763     static public class SimpleSpread implements Spread {
    764         static final Spread FLAT = new SimpleSpread(1.0);
    765         boolean flat = false;
    766         double aa, bb, cc;
    767         public SimpleSpread(double maxWeight) {
    768             if (maxWeight > 0.999 && maxWeight < 1.001) {
    769                 flat = true;
    770             } else {
    771                 double q = (maxWeight - 1.0);
    772                 aa = -1/q;
    773                 bb = 1/(q*q);
    774                 cc = (2.0+q)/q;
    775            }
    776         }
    777         public double spread(double value) {
    778             if (flat) return value;
    779             value = aa + Math.sqrt(bb + cc*value);
    780             if (value < 0.0) return 0.0;    // catch math gorp
    781             if (value >= 1.0) return 1.0;
    782             return value;
    783         }
    784     }
    785     static public int pick(Spread spread, Random random, int start, int end) {
    786         return start + (int)(spread.spread(random.nextDouble()) * (end + 1 - start));
    787     }
    788 
    789    */
    790 
    791 
    792 }