001 /*
002 $Id: Reduction.java,v 1.3 2005/04/12 15:04:59 jstrachan Exp $
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 /**
058 * A syntax reduction, produced by the <code>Parser</code>.
059 *
060 * @see Parser
061 * @see Token
062 * @see CSTNode
063 * @see Types
064 *
065 * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
066 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
067 *
068 * @version $Id: Reduction.java,v 1.3 2005/04/12 15:04:59 jstrachan Exp $
069 */
070
071 public class Reduction extends CSTNode
072 {
073 public static final Reduction EMPTY = new Reduction();
074
075
076 //---------------------------------------------------------------------------
077 // INITIALIZATION AND SUCH
078
079 private List elements = null; // The set of child nodes
080 private boolean marked = false; // Used for completion marking by some parts of the parser
081
082
083 /**
084 * Initializes the <code>Reduction</code> with the specified root.
085 */
086
087 public Reduction( Token root )
088 {
089 elements = new ArrayList();
090 set( 0, root );
091 }
092
093
094 /**
095 * Initializes the <code>Reduction</code> to empty.
096 */
097
098 private Reduction()
099 {
100 elements = Collections.EMPTY_LIST;
101 }
102
103
104 /**
105 * Creates a new <code>Reduction</code> with <code>Token.NULL</code>
106 * as it's root.
107 */
108
109 public static Reduction newContainer()
110 {
111 return new Reduction( Token.NULL );
112 }
113
114
115
116
117 //---------------------------------------------------------------------------
118 // MEMBER ACCESS
119
120
121 /**
122 * Returns true if the node is completely empty (no root, even).
123 */
124
125 public boolean isEmpty()
126 {
127 return size() == 0;
128 }
129
130
131
132 /**
133 * Returns the number of elements in the node.
134 */
135
136 public int size()
137 {
138 return elements.size();
139 }
140
141
142
143 /**
144 * Returns the specified element, or null.
145 */
146
147 public CSTNode get( int index )
148 {
149 CSTNode element = null;
150
151 if( index < size() )
152 {
153 element = (CSTNode)elements.get( index );
154 }
155
156 return element;
157 }
158
159
160
161 /**
162 * Returns the root of the node, the Token that indicates it's
163 * type. Returns null if there is no root (usually only if the
164 * node is a placeholder of some kind -- see isEmpty()).
165 */
166
167 public Token getRoot()
168 {
169 if( size() > 0 )
170 {
171 return (Token)elements.get(0);
172 }
173 else
174 {
175 return null;
176 }
177 }
178
179
180
181 /**
182 * Marks the node a complete expression.
183 */
184
185 public void markAsExpression()
186 {
187 marked = true;
188 }
189
190
191
192 /**
193 * Returns true if the node is a complete expression.
194 */
195
196 public boolean isAnExpression()
197 {
198 if( isA(Types.COMPLEX_EXPRESSION) )
199 {
200 return true;
201 }
202
203 return marked;
204 }
205
206
207
208
209 //---------------------------------------------------------------------------
210 // OPERATIONS
211
212
213 /**
214 * Adds an element to the node.
215 */
216
217 public CSTNode add( CSTNode element )
218 {
219 return set( size(), element );
220 }
221
222
223
224 /**
225 * Sets an element in at the specified index.
226 */
227
228 public CSTNode set( int index, CSTNode element )
229 {
230
231 if( elements == null )
232 {
233 throw new GroovyBugError( "attempt to set() on a EMPTY Reduction" );
234 }
235
236 if( index == 0 && !(element instanceof Token) )
237 {
238
239 //
240 // It's not the greatest of design that the interface allows this, but it
241 // is a tradeoff with convenience, and the convenience is more important.
242
243 throw new GroovyBugError( "attempt to set() a non-Token as root of a Reduction" );
244 }
245
246
247 //
248 // Fill slots with nulls, if necessary.
249
250 int count = elements.size();
251 if( index >= count )
252 {
253 for( int i = count; i <= index; i++ )
254 {
255 elements.add( null );
256 }
257 }
258
259 //
260 // Then set in the element.
261
262 elements.set( index, element );
263
264 return element;
265 }
266
267
268
269 /**
270 * Removes a node from the <code>Reduction</code>. You cannot remove
271 * the root node (index 0).
272 */
273
274 public CSTNode remove( int index )
275 {
276 if( index < 1 )
277 {
278 throw new GroovyBugError( "attempt to remove() root node of Reduction" );
279 }
280
281 return (CSTNode)elements.remove( index );
282 }
283
284
285
286 /**
287 * Creates a <code>Reduction</code> from this node. Returns self if the
288 * node is already a <code>Reduction</code>.
289 */
290
291 public Reduction asReduction()
292 {
293 return this;
294 }
295
296 }
297