/* * xtc - The eXTensible Compiler * Copyright (C) 2004-2007 Robert Grimm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.parser; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * A sequence of grammar elements. * * <p />A sequence may have an optional name. However, this name is * not considered when comparing sequences for equality. * * @author Robert Grimm * @version $Revision: 1.30 $ */ public class Sequence extends Element { /** The optional name. */ public SequenceName name; /** The ordered list of grammar elements. */ public List<Element> elements; /** Create a new, empty sequence. */ public Sequence() { this(null, new ArrayList<Element>()); } /** * Create a new, empty sequence with the specified capacity. * * @param capacity The capacity. */ public Sequence(int capacity) { this(null, new ArrayList<Element>(capacity)); } /** * Create a new sequence. * * @param elements The list of elements. */ public Sequence(final List<Element> elements) { this(null, elements); } /** * Create a new sequence. * * @param name The name. * @param elements The list of elements. */ public Sequence(final SequenceName name, final List<Element> elements) { this.name = name; this.elements = elements; } /** * Create a new sequence with the specified element. If the element * is another sequence, the new sequence has the same elements but * is a copy. Otherwise, the new sequence has the specified element * as its only element. In either case, the new sequence has the * element's location. * * @param element The element. */ public Sequence(final Element element) { if (element instanceof Sequence) { Sequence s = (Sequence)element; elements = new ArrayList<Element>(s.elements); name = s.name; } else { elements = new ArrayList<Element>(1); elements.add(element); } setLocation(element); } public Tag tag() { return Tag.SEQUENCE; } /** * Remove all elements from this sequence. * * @return This sequence. */ public Sequence clear() { elements.clear(); return this; } /** * Add the specified element to this sequence. * * @param e The element to add. * @return This sequence. */ public Sequence add(Element e) { elements.add(e); return this; } /** * Add all elements in the specified list to this sequence. * * @param l The list of elements. * @return This sequence. */ public Sequence addAll(List<Element> l) { elements.addAll(l); return this; } /** * Determine whether this sequence is empty. * * @return <code>true</code> if this is an empty sequence. */ public boolean isEmpty() { return elements.isEmpty(); } /** * Get the size of this sequence. * * @return The size. */ public int size() { return elements.size(); } /** * Get the element at the specified index. * * @param idx The index. * @return The element at that position. * @throws IndexOutOfBoundsException * Signals that the index is out of range. */ public Element get(final int idx) { return elements.get(idx); } /** * Determine whether this sequence's last element is an ordered * choice. * * @return <code>true</code> if the last element is a choice. */ public boolean hasTrailingChoice() { final int size = elements.size(); return (0 < size) && (elements.get(size-1) instanceof OrderedChoice); } /** * Create a new subsequence from the specified start index. The new * subsequence ends with the last element of this sequence. * * @param start The inclusive start index. * @return The subsequence. * @throws IndexOutOfBoundsException * Signals that the index is out of range. */ public Sequence subSequence(final int start) { return subSequence(start, elements.size()); } /** * Create a new subsequence for the specified indices. * * @param start The inclusive start index. * @param end The exclusive end index. * @return The subsequence. * @throws IndexOutOfBoundsException * Signals that the index is out of range. */ public Sequence subSequence(final int start, final int end) { // The subsequence has the original's source location. Sequence s = new Sequence(new ArrayList<Element>(elements.subList(start, end))); s.setLocation(this); return s; } public int hashCode() { return elements.hashCode(); } public boolean equals(final Object o) { if (this == o) return true; if (! (o instanceof Sequence)) return false; return elements.equals(((Sequence)o).elements); } public void write(Appendable out) throws IOException { out.append('('); boolean first = true; for (Element e : elements) { if (first) { first = false; } else { out.append(' '); } e.write(out); } out.append(')'); } /** * Ensure that the specified element is a sequence. If the specified * element is not a sequence, a new sequence with the specified * element as its only element is returned; the newly created * sequence has the element's location. * * @param e The element. * @return The element in/as a sequence. */ public static Sequence ensure(final Element e) { if (e instanceof Sequence) { return (Sequence)e; } else { Sequence s = new Sequence(e); s.setLocation(e); return s; } } }