001: package org.ofbiz.rules.parse;
002:
003: import java.util.*;
004:
005: /**
006: * <p><b>Title:</b> Terminal
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>Terminal</code> is a parser that is not a
031: * composition of other parsers. Terminals are "terminal"
032: * because they do not pass matching work on to other
033: * parsers. The criterion that terminals use to check a
034: * match is something other than another parser. Terminals
035: * are also the only parsers that advance an assembly.
036: *
037: * @author Steven J. Metsker
038: * @version 1.0
039: */
040: public class Terminal extends Parser {
041:
042: /**
043: * whether or not this terminal should push itself upon an
044: * assembly's stack after a successful match
045: */
046: protected boolean discard = false;
047:
048: /**
049: * Constructs an unnamed terminal.
050: */
051: public Terminal() {
052: }
053:
054: /**
055: * Constructs a terminal with the given name.
056: *
057: * @param String A name to be known by.
058: */
059: public Terminal(String name) {
060: super (name);
061: }
062:
063: /**
064: * Accept a "visitor" and a collection of previously visited
065: * parsers.
066: *
067: * @param pv the visitor to accept
068: *
069: * @param visited a collection of previously visited parsers
070: */
071: public void accept(ParserVisitor pv, List visited) {
072: pv.visitTerminal(this , visited);
073: }
074:
075: /**
076: * A convenience method that sets discarding to be true.
077: *
078: * @return this
079: */
080: public Terminal discard() {
081: return setDiscard(true);
082: }
083:
084: /**
085: * Given a collection of assemblies, this method matches
086: * this terminal against all of them, and returns a new
087: * collection of the assemblies that result from the
088: * matches.
089: *
090: * @return a List of assemblies that result from
091: * matching against a beginning set of assemblies
092: *
093: * @param in a vector of assemblies to match against
094: *
095: */
096: public List match(List in) {
097: List out = new ArrayList();
098: Enumeration e = Collections.enumeration(in);
099:
100: while (e.hasMoreElements()) {
101: Assembly a = (Assembly) e.nextElement();
102: Assembly b = matchOneAssembly(a);
103:
104: if (b != null) {
105: out.add(b);
106: }
107: }
108: return out;
109: }
110:
111: /**
112: * Returns an assembly equivalent to the supplied assembly,
113: * except that this terminal will have been removed from the
114: * front of the assembly. As with any parser, if the
115: * match succeeds, this terminal's assembler will work on
116: * the assembly. If the match fails, this method returns
117: * null.
118: *
119: * @param Assembly the assembly to match against
120: *
121: * @return a copy of the incoming assembly, advanced by this
122: * terminal
123: */
124: protected Assembly matchOneAssembly(Assembly in) {
125: if (!in.hasMoreElements()) {
126: return null;
127: }
128: if (qualifies(in.peek())) {
129: Assembly out = (Assembly) in.clone();
130: Object o = out.nextElement();
131:
132: if (!discard) {
133: out.push(o);
134: }
135: return out;
136: }
137: return null;
138: }
139:
140: /**
141: * The mechanics of matching are the same for many terminals,
142: * except for the check that the next element on the assembly
143: * qualifies as the type of terminal this terminal looks for.
144: * This method performs that check.
145: *
146: * @param Object an element from a assembly
147: *
148: * @return true, if the object is the kind of terminal this
149: * parser seeks
150: */
151: protected boolean qualifies(Object o) {
152: return true;
153: }
154:
155: /**
156: * By default, create a collection with this terminal's
157: * string representation of itself. (Most subclasses
158: * override this.)
159: */
160: public List randomExpansion(int maxDepth, int depth) {
161: List v = new ArrayList();
162:
163: v.add(this .toString());
164: return v;
165: }
166:
167: /**
168: * By default, terminals push themselves upon a assembly's
169: * stack, after a successful match. This routine will turn
170: * off (or turn back on) that behavior.
171: *
172: * @param boolean true, if this terminal should push
173: * itself on a assembly's stack
174: *
175: * @return this
176: */
177: public Terminal setDiscard(boolean discard) {
178: this .discard = discard;
179: return this ;
180: }
181:
182: /**
183: * Returns a textual description of this parser.
184: */
185: protected String unvisitedString(List visited) {
186: return "any";
187: }
188: }
|