001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2004-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.parser;
020:
021: import java.io.IOException;
022:
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: /**
027: * A sequence of grammar elements.
028: *
029: * <p />A sequence may have an optional name. However, this name is
030: * not considered when comparing sequences for equality.
031: *
032: * @author Robert Grimm
033: * @version $Revision: 1.30 $
034: */
035: public class Sequence extends Element {
036:
037: /** The optional name. */
038: public SequenceName name;
039:
040: /** The ordered list of grammar elements. */
041: public List<Element> elements;
042:
043: /** Create a new, empty sequence. */
044: public Sequence() {
045: this (null, new ArrayList<Element>());
046: }
047:
048: /**
049: * Create a new, empty sequence with the specified capacity.
050: *
051: * @param capacity The capacity.
052: */
053: public Sequence(int capacity) {
054: this (null, new ArrayList<Element>(capacity));
055: }
056:
057: /**
058: * Create a new sequence.
059: *
060: * @param elements The list of elements.
061: */
062: public Sequence(final List<Element> elements) {
063: this (null, elements);
064: }
065:
066: /**
067: * Create a new sequence.
068: *
069: * @param name The name.
070: * @param elements The list of elements.
071: */
072: public Sequence(final SequenceName name,
073: final List<Element> elements) {
074: this .name = name;
075: this .elements = elements;
076: }
077:
078: /**
079: * Create a new sequence with the specified element. If the element
080: * is another sequence, the new sequence has the same elements but
081: * is a copy. Otherwise, the new sequence has the specified element
082: * as its only element. In either case, the new sequence has the
083: * element's location.
084: *
085: * @param element The element.
086: */
087: public Sequence(final Element element) {
088: if (element instanceof Sequence) {
089: Sequence s = (Sequence) element;
090:
091: elements = new ArrayList<Element>(s.elements);
092: name = s.name;
093: } else {
094: elements = new ArrayList<Element>(1);
095: elements.add(element);
096: }
097: setLocation(element);
098: }
099:
100: public Tag tag() {
101: return Tag.SEQUENCE;
102: }
103:
104: /**
105: * Remove all elements from this sequence.
106: *
107: * @return This sequence.
108: */
109: public Sequence clear() {
110: elements.clear();
111: return this ;
112: }
113:
114: /**
115: * Add the specified element to this sequence.
116: *
117: * @param e The element to add.
118: * @return This sequence.
119: */
120: public Sequence add(Element e) {
121: elements.add(e);
122: return this ;
123: }
124:
125: /**
126: * Add all elements in the specified list to this sequence.
127: *
128: * @param l The list of elements.
129: * @return This sequence.
130: */
131: public Sequence addAll(List<Element> l) {
132: elements.addAll(l);
133: return this ;
134: }
135:
136: /**
137: * Determine whether this sequence is empty.
138: *
139: * @return <code>true</code> if this is an empty sequence.
140: */
141: public boolean isEmpty() {
142: return elements.isEmpty();
143: }
144:
145: /**
146: * Get the size of this sequence.
147: *
148: * @return The size.
149: */
150: public int size() {
151: return elements.size();
152: }
153:
154: /**
155: * Get the element at the specified index.
156: *
157: * @param idx The index.
158: * @return The element at that position.
159: * @throws IndexOutOfBoundsException
160: * Signals that the index is out of range.
161: */
162: public Element get(final int idx) {
163: return elements.get(idx);
164: }
165:
166: /**
167: * Determine whether this sequence's last element is an ordered
168: * choice.
169: *
170: * @return <code>true</code> if the last element is a choice.
171: */
172: public boolean hasTrailingChoice() {
173: final int size = elements.size();
174: return (0 < size)
175: && (elements.get(size - 1) instanceof OrderedChoice);
176: }
177:
178: /**
179: * Create a new subsequence from the specified start index. The new
180: * subsequence ends with the last element of this sequence.
181: *
182: * @param start The inclusive start index.
183: * @return The subsequence.
184: * @throws IndexOutOfBoundsException
185: * Signals that the index is out of range.
186: */
187: public Sequence subSequence(final int start) {
188: return subSequence(start, elements.size());
189: }
190:
191: /**
192: * Create a new subsequence for the specified indices.
193: *
194: * @param start The inclusive start index.
195: * @param end The exclusive end index.
196: * @return The subsequence.
197: * @throws IndexOutOfBoundsException
198: * Signals that the index is out of range.
199: */
200: public Sequence subSequence(final int start, final int end) {
201: // The subsequence has the original's source location.
202: Sequence s = new Sequence(new ArrayList<Element>(elements
203: .subList(start, end)));
204: s.setLocation(this );
205: return s;
206: }
207:
208: public int hashCode() {
209: return elements.hashCode();
210: }
211:
212: public boolean equals(final Object o) {
213: if (this == o)
214: return true;
215: if (!(o instanceof Sequence))
216: return false;
217: return elements.equals(((Sequence) o).elements);
218: }
219:
220: public void write(Appendable out) throws IOException {
221: out.append('(');
222: boolean first = true;
223: for (Element e : elements) {
224: if (first) {
225: first = false;
226: } else {
227: out.append(' ');
228: }
229: e.write(out);
230: }
231: out.append(')');
232: }
233:
234: /**
235: * Ensure that the specified element is a sequence. If the specified
236: * element is not a sequence, a new sequence with the specified
237: * element as its only element is returned; the newly created
238: * sequence has the element's location.
239: *
240: * @param e The element.
241: * @return The element in/as a sequence.
242: */
243: public static Sequence ensure(final Element e) {
244: if (e instanceof Sequence) {
245: return (Sequence) e;
246: } else {
247: Sequence s = new Sequence(e);
248: s.setLocation(e);
249: return s;
250: }
251: }
252:
253: }
|