| /* |
| * Copyright 2003-2007 the original author or authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.codehaus.groovy.syntax; |
| |
| import org.codehaus.groovy.GroovyBugError; |
| |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| |
| |
| /** |
| * A syntax reduction, produced by the <code>Parser</code>. |
| * |
| * @see antlr.Parser |
| * @see Token |
| * @see CSTNode |
| * @see Types |
| * |
| * @author <a href="mailto:bob@werken.com">bob mcwhirter</a> |
| * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a> |
| * |
| * @version $Id$ |
| */ |
| |
| public class Reduction extends CSTNode |
| { |
| public static final Reduction EMPTY = new Reduction(); |
| |
| |
| //--------------------------------------------------------------------------- |
| // INITIALIZATION AND SUCH |
| |
| private List elements = null; // The set of child nodes |
| private boolean marked = false; // Used for completion marking by some parts of the parser |
| |
| |
| /** |
| * Initializes the <code>Reduction</code> with the specified root. |
| */ |
| |
| public Reduction( Token root ) |
| { |
| elements = new ArrayList(); |
| set( 0, root ); |
| } |
| |
| |
| /** |
| * Initializes the <code>Reduction</code> to empty. |
| */ |
| |
| private Reduction() |
| { |
| elements = Collections.EMPTY_LIST; |
| } |
| |
| |
| /** |
| * Creates a new <code>Reduction</code> with <code>Token.NULL</code> |
| * as it's root. |
| */ |
| |
| public static Reduction newContainer() |
| { |
| return new Reduction( Token.NULL ); |
| } |
| |
| |
| |
| |
| //--------------------------------------------------------------------------- |
| // MEMBER ACCESS |
| |
| |
| /** |
| * Returns true if the node is completely empty (no root, even). |
| */ |
| |
| public boolean isEmpty() |
| { |
| return size() == 0; |
| } |
| |
| |
| |
| /** |
| * Returns the number of elements in the node. |
| */ |
| |
| public int size() |
| { |
| return elements.size(); |
| } |
| |
| |
| |
| /** |
| * Returns the specified element, or null. |
| */ |
| |
| public CSTNode get( int index ) |
| { |
| CSTNode element = null; |
| |
| if( index < size() ) |
| { |
| element = (CSTNode)elements.get( index ); |
| } |
| |
| return element; |
| } |
| |
| |
| |
| /** |
| * Returns the root of the node, the Token that indicates it's |
| * type. Returns null if there is no root (usually only if the |
| * node is a placeholder of some kind -- see isEmpty()). |
| */ |
| |
| public Token getRoot() |
| { |
| if( size() > 0 ) |
| { |
| return (Token)elements.get(0); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| |
| |
| /** |
| * Marks the node a complete expression. |
| */ |
| |
| public void markAsExpression() |
| { |
| marked = true; |
| } |
| |
| |
| |
| /** |
| * Returns true if the node is a complete expression. |
| */ |
| |
| public boolean isAnExpression() |
| { |
| if( isA(Types.COMPLEX_EXPRESSION) ) |
| { |
| return true; |
| } |
| |
| return marked; |
| } |
| |
| |
| |
| |
| //--------------------------------------------------------------------------- |
| // OPERATIONS |
| |
| |
| /** |
| * Adds an element to the node. |
| */ |
| |
| public CSTNode add( CSTNode element ) |
| { |
| return set( size(), element ); |
| } |
| |
| |
| |
| /** |
| * Sets an element in at the specified index. |
| */ |
| |
| public CSTNode set( int index, CSTNode element ) |
| { |
| |
| if( elements == null ) |
| { |
| throw new GroovyBugError( "attempt to set() on a EMPTY Reduction" ); |
| } |
| |
| if( index == 0 && !(element instanceof Token) ) |
| { |
| |
| // |
| // It's not the greatest of design that the interface allows this, but it |
| // is a tradeoff with convenience, and the convenience is more important. |
| |
| throw new GroovyBugError( "attempt to set() a non-Token as root of a Reduction" ); |
| } |
| |
| |
| // |
| // Fill slots with nulls, if necessary. |
| |
| int count = elements.size(); |
| if( index >= count ) |
| { |
| for( int i = count; i <= index; i++ ) |
| { |
| elements.add( null ); |
| } |
| } |
| |
| // |
| // Then set in the element. |
| |
| elements.set( index, element ); |
| |
| return element; |
| } |
| |
| |
| |
| /** |
| * Removes a node from the <code>Reduction</code>. You cannot remove |
| * the root node (index 0). |
| */ |
| |
| public CSTNode remove( int index ) |
| { |
| if( index < 1 ) |
| { |
| throw new GroovyBugError( "attempt to remove() root node of Reduction" ); |
| } |
| |
| return (CSTNode)elements.remove( index ); |
| } |
| |
| |
| |
| /** |
| * Creates a <code>Reduction</code> from this node. Returns self if the |
| * node is already a <code>Reduction</code>. |
| */ |
| |
| public Reduction asReduction() |
| { |
| return this; |
| } |
| |
| } |
| |