blob: 446d1233c8ab54de5279aae53a4cab986955ed19 [file] [log] [blame]
/*
* 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.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A syntax reduction, produced by the <code>Parser</code>.
*
* @see antlr.Parser
* @see Token
* @see CSTNode
* @see Types
*/
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;
}
}