001: /*
002: $Id: Reduction.java 4032 2006-08-30 07:18:49Z mguillem $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046:
047: package org.codehaus.groovy.syntax;
048:
049: import org.codehaus.groovy.GroovyBugError;
050: import org.codehaus.groovy.syntax.Token;
051:
052: import java.util.List;
053: import java.util.ArrayList;
054: import java.util.Collections;
055:
056: /**
057: * A syntax reduction, produced by the <code>Parser</code>.
058: *
059: * @see antlr.Parser
060: * @see Token
061: * @see CSTNode
062: * @see Types
063: *
064: * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
065: * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
066: *
067: * @version $Id: Reduction.java 4032 2006-08-30 07:18:49Z mguillem $
068: */
069:
070: public class Reduction extends CSTNode {
071: public static final Reduction EMPTY = new Reduction();
072:
073: //---------------------------------------------------------------------------
074: // INITIALIZATION AND SUCH
075:
076: private List elements = null; // The set of child nodes
077: private boolean marked = false; // Used for completion marking by some parts of the parser
078:
079: /**
080: * Initializes the <code>Reduction</code> with the specified root.
081: */
082:
083: public Reduction(Token root) {
084: elements = new ArrayList();
085: set(0, root);
086: }
087:
088: /**
089: * Initializes the <code>Reduction</code> to empty.
090: */
091:
092: private Reduction() {
093: elements = Collections.EMPTY_LIST;
094: }
095:
096: /**
097: * Creates a new <code>Reduction</code> with <code>Token.NULL</code>
098: * as it's root.
099: */
100:
101: public static Reduction newContainer() {
102: return new Reduction(Token.NULL);
103: }
104:
105: //---------------------------------------------------------------------------
106: // MEMBER ACCESS
107:
108: /**
109: * Returns true if the node is completely empty (no root, even).
110: */
111:
112: public boolean isEmpty() {
113: return size() == 0;
114: }
115:
116: /**
117: * Returns the number of elements in the node.
118: */
119:
120: public int size() {
121: return elements.size();
122: }
123:
124: /**
125: * Returns the specified element, or null.
126: */
127:
128: public CSTNode get(int index) {
129: CSTNode element = null;
130:
131: if (index < size()) {
132: element = (CSTNode) elements.get(index);
133: }
134:
135: return element;
136: }
137:
138: /**
139: * Returns the root of the node, the Token that indicates it's
140: * type. Returns null if there is no root (usually only if the
141: * node is a placeholder of some kind -- see isEmpty()).
142: */
143:
144: public Token getRoot() {
145: if (size() > 0) {
146: return (Token) elements.get(0);
147: } else {
148: return null;
149: }
150: }
151:
152: /**
153: * Marks the node a complete expression.
154: */
155:
156: public void markAsExpression() {
157: marked = true;
158: }
159:
160: /**
161: * Returns true if the node is a complete expression.
162: */
163:
164: public boolean isAnExpression() {
165: if (isA(Types.COMPLEX_EXPRESSION)) {
166: return true;
167: }
168:
169: return marked;
170: }
171:
172: //---------------------------------------------------------------------------
173: // OPERATIONS
174:
175: /**
176: * Adds an element to the node.
177: */
178:
179: public CSTNode add(CSTNode element) {
180: return set(size(), element);
181: }
182:
183: /**
184: * Sets an element in at the specified index.
185: */
186:
187: public CSTNode set(int index, CSTNode element) {
188:
189: if (elements == null) {
190: throw new GroovyBugError(
191: "attempt to set() on a EMPTY Reduction");
192: }
193:
194: if (index == 0 && !(element instanceof Token)) {
195:
196: //
197: // It's not the greatest of design that the interface allows this, but it
198: // is a tradeoff with convenience, and the convenience is more important.
199:
200: throw new GroovyBugError(
201: "attempt to set() a non-Token as root of a Reduction");
202: }
203:
204: //
205: // Fill slots with nulls, if necessary.
206:
207: int count = elements.size();
208: if (index >= count) {
209: for (int i = count; i <= index; i++) {
210: elements.add(null);
211: }
212: }
213:
214: //
215: // Then set in the element.
216:
217: elements.set(index, element);
218:
219: return element;
220: }
221:
222: /**
223: * Removes a node from the <code>Reduction</code>. You cannot remove
224: * the root node (index 0).
225: */
226:
227: public CSTNode remove(int index) {
228: if (index < 1) {
229: throw new GroovyBugError(
230: "attempt to remove() root node of Reduction");
231: }
232:
233: return (CSTNode) elements.remove(index);
234: }
235:
236: /**
237: * Creates a <code>Reduction</code> from this node. Returns self if the
238: * node is already a <code>Reduction</code>.
239: */
240:
241: public Reduction asReduction() {
242: return this;
243: }
244:
245: }
|