blob: 4d1aed02d00b33d9d558841a5553ad83bcd39f75 [file] [log] [blame]
/*
* 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;
}
}