/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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> */ 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; } }