001: package org.ofbiz.rules.parse;
002:
003: import java.util.*;
004:
005: /**
006: * <p><b>Title:</b> Repetition
007: * <p><b>Description:</b> None
008: * <p>Copyright (c) 1999 Steven J. Metsker.
009: * <p>Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
010: *
011: * <p>Permission is hereby granted, free of charge, to any person obtaining a
012: * copy of this software and associated documentation files (the "Software"),
013: * to deal in the Software without restriction, including without limitation
014: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
015: * and/or sell copies of the Software, and to permit persons to whom the
016: * Software is furnished to do so, subject to the following conditions:
017: *
018: * <p>The above copyright notice and this permission notice shall be included
019: * in all copies or substantial portions of the Software.
020: *
021: * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
022: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
023: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
024: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
025: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
026: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
027: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
028: *
029: * <br>
030: * <p>A <code>Repetition</code> matches its underlying parser
031: * repeatedly against a assembly.
032: *
033: * @author Steven J. Metsker
034: * @version 1.0
035: */
036:
037: public class Repetition extends Parser {
038:
039: /**
040: * the parser this parser is a repetition of
041: */
042: protected Parser subparser;
043:
044: /**
045: * the width of a random expansion
046: */
047: protected static final int EXPWIDTH = 4;
048:
049: /**
050: * an assembler to apply at the beginning of a match
051: */
052: protected Assembler preAssembler;
053:
054: /**
055: * Constructs a repetition of the given parser.
056: *
057: * @param parser the parser to repeat
058: *
059: * @return a repetiton that will match the given
060: * parser repeatedly in successive matches
061: */
062: public Repetition(Parser p) {
063: this (p, null);
064: }
065:
066: /**
067: * Constructs a repetition of the given parser with the
068: * given name.
069: *
070: * @param Parser the parser to repeat
071: *
072: * @param String a name to be known by
073: *
074: * @return a repetiton that will match the given
075: * parser repeatedly in successive matches
076: */
077: public Repetition(Parser subparser, String name) {
078: super (name);
079: this .subparser = subparser;
080: }
081:
082: /**
083: * Accept a "visitor" and a collection of previously visited
084: * parsers.
085: *
086: * @param pv the visitor to accept
087: *
088: * @param visited a collection of previously visited parsers
089: */
090: public void accept(ParserVisitor pv, List visited) {
091: pv.visitRepetition(this , visited);
092: }
093:
094: /**
095: * Return this parser's subparser.
096: *
097: * @return Parser this parser's subparser
098: */
099: public Parser getSubparser() {
100: return subparser;
101: }
102:
103: /**
104: * Given a set of assemblies, this method applies a preassembler
105: * to all of them, matches its subparser repeatedly against each
106: * of them, applies its post-assembler against each, and returns
107: * a new set of the assemblies that result from the matches.
108: * <p>
109: * For example, matching the regular expression <code>a*
110: * </code> against <code>{^aaab}</code> results in <code>
111: * {^aaab, a^aab, aa^ab, aaa^b}</code>.
112: *
113: * @return a List of assemblies that result from
114: * matching against a beginning set of assemblies
115: *
116: * @param in a vector of assemblies to match against
117: *
118: */
119: public List match(List in) {
120: if (preAssembler != null) {
121: Enumeration e = Collections.enumeration(in);
122:
123: while (e.hasMoreElements()) {
124: preAssembler.workOn((Assembly) e.nextElement());
125: }
126: }
127: List out = elementClone(in);
128: List s = in; // a working state
129:
130: while (!s.isEmpty()) {
131: s = subparser.matchAndAssemble(s);
132: add(out, s);
133: }
134: return out;
135: }
136:
137: /**
138: * Create a collection of random elements that correspond to
139: * this repetition.
140: */
141: protected List randomExpansion(int maxDepth, int depth) {
142: List v = new ArrayList();
143:
144: if (depth >= maxDepth) {
145: return v;
146: }
147:
148: int n = (int) (EXPWIDTH * Math.random());
149:
150: for (int j = 0; j < n; j++) {
151: List w = subparser.randomExpansion(maxDepth, depth++);
152: Enumeration e = Collections.enumeration(w);
153:
154: while (e.hasMoreElements()) {
155: v.add(e.nextElement());
156: }
157: }
158: return v;
159: }
160:
161: /**
162: * Sets the object that will work on every assembly before
163: * matching against it.
164: *
165: * @param Assembler the assembler to apply
166: *
167: * @return Parser this
168: */
169: public Parser setPreAssembler(Assembler preAssembler) {
170: this .preAssembler = preAssembler;
171: return this ;
172: }
173:
174: /**
175: * Returns a textual description of this parser.
176: */
177: protected String unvisitedString(List visited) {
178: return subparser.toString(visited) + "*";
179: }
180: }
|