blob: 46346d7070e5d55bc906178f58d93f7a5bf1186e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.gymnast.runtime.core.ast;
import java.util.ArrayList;
/**
*
* @author cjdaly@us.ibm.com
*/
public abstract class ASTNodeImpl implements ASTNode {
private static final TokenInfo NO_TOKEN = new TokenInfo(null, -1, -1);
private final TokenInfo _tokenInfo;
public ASTNodeImpl() {
_tokenInfo = NO_TOKEN;
}
public ASTNodeImpl(TokenInfo tokenInfo) {
_tokenInfo = tokenInfo;
}
public ASTNodeImpl(int offset, int type, String text) {
_tokenInfo = new TokenInfo(text, offset, type);
}
//
// local data accessors
//
public final int getOffset() {
return _tokenInfo.getOffset();
}
public int getTokenType() {
return _tokenInfo.getType();
}
public String getText() {
return _tokenInfo.getText();
}
public final int getTextLength() {
if (getText() == null) return 0;
else return getText().length();
}
//
// basic children methods
//
/**
* @return the number of children of this ASTNode
*/
public abstract int getChildCount();
/**
* @param index the index of a child ASTNode to get
* @return the child ASTNode at the given index
* @throws IndexOutOfBoundsException when the index is out of bounds
*/
public abstract ASTNode getChild(int index);
public final boolean hasChildren() {
return getChildCount() != 0;
}
public final ASTNode getFirstChild() {
if (getChildCount() == 0) return null;
return getChild(0);
}
public final ASTNode getLastChild() {
if (getChildCount() == 0) return null;
else return getChild(getChildCount() - 1);
}
// TODO: this is slow ... push it up to the implementors of getChildCount()
// and getChild(i) or get rid of it.
public ASTNode[] getChildren()
{
ArrayList list = new ArrayList();
for (int i = 0; i < getChildCount(); i++) {
list.add(getChild(i));
}
return (ASTNode[]) list.toArray(new ASTNode[list.size()]);
}
//
// parent methods
//
/**
* @return the parent of this ASTNode or null if this is the root node of a tree
*/
public abstract ASTNode getParent();
public final ASTNode getRoot() {
ASTNode root = this;
while (root.getParent() != null) {
root = root.getParent();
}
return root;
}
public final boolean isRoot() {
return (getParent() == null);
}
//
// derived child methods
//
public final boolean isTokenNode() {
return ((hasChildren() == false) && (getText() != null));
}
public final int getRangeStart() {
ASTNode firstToken = getFirstToken();
if (firstToken == null) return -1;
else return firstToken.getOffset();
}
public final int getRangeLength() {
ASTNode lastToken = getLastToken();
if (lastToken == null) return 0;
else return (lastToken.getOffset() + lastToken.getTextLength()) - getRangeStart();
}
public final int getRangeEnd() {
return getRangeStart() + getRangeLength();
}
public final ASTNode getFirstLeaf() {
if (!hasChildren()) return this;
ASTNode first = getFirstChild();
return first.getFirstLeaf();
}
public final ASTNode getLastLeaf() {
if (!hasChildren()) return this;
ASTNode last = getLastChild();
return last.getLastLeaf();
}
public final ASTNode getFirstToken() {
if (!hasChildren()) {
if (isTokenNode()) return this;
else return null;
}
else {
for (int i = 0; i < getChildCount(); i++) {
ASTNode n = getChild(i);
ASTNode temp = n.getFirstToken();
if (temp != null) return temp;
}
return null;
}
}
public final ASTNode getLastToken() {
if (!hasChildren()) {
if (isTokenNode()) return this;
else return null;
}
else {
for (int i = getChildCount()-1; i >= 0; i--) {
ASTNode n = getChild(i);
ASTNode temp = n.getLastToken();
if (temp != null) return temp;
}
return null;
}
}
/**
* @param offset in the source text
* @param length in the source text
* @param filter list of classes to include or exclude
* @param inclusionFilter true to include this if it matches the filter
* and false to exclude this node if it matches filter
* @return ASTNode best matching the given position
*
* Search through the parse tree for the most specific (deepest) node
* that spans the given position.
*/
public final ASTNode getNodeAt(int offset, int length, Class[] filter, boolean inclusionFilter) {
boolean nodeTypeOk = true;
if (filter != null) {
boolean foundMatch = false;
for (int i = 0; i < filter.length; i++){
if (filter[i].isInstance(this)) {
foundMatch = true;
}
}
nodeTypeOk = !(inclusionFilter ^ foundMatch);
}
if ((offset >= getRangeStart()) && (offset + length < getRangeEnd())){
for (int i = 0; i < getChildCount(); i++) {
ASTNode child = getChild(i);
ASTNode x = child.getNodeAt(offset, length, filter, inclusionFilter);
if (x != null) return x;
}
if (nodeTypeOk) return this;
}
return null;
}
public final ASTNode getNodeAt(int offset, int length, Class filter, boolean inclusionFilter) {
return getNodeAt(offset, length, new Class[] { filter }, inclusionFilter);
}
public final ASTNode getNodeAt(int offset, Class filter, boolean inclusionFilter) {
return getNodeAt(offset, 0, new Class[] { filter }, inclusionFilter);
}
public final ASTNode getNodeAt(int offset, int length) {
return getNodeAt(offset, length, new Class[] { }, false);
}
/////////////////////////////////////////////////////////////////////////////////////
// BEGIN Debug method section
public final void checkTokenOffsets(String input) {
int offset = getOffset();
if (offset != -1) {
String tokenText = getText();
if (tokenText != null) {
try {
String inputText = input.substring(offset, offset + tokenText.length());
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
for (int i = 0; i < getChildCount(); i++) {
ASTNode child = getChild(i);
child.checkTokenOffsets(input);
}
}
public void dump(int level){
for (int i = 0; i < getChildCount(); i++) {
ASTNode child = getChild(i);
child.dump(level+1);
}
}
//
public String getTypeName()
{
String fullName = this.getClass().getName();
int pos = fullName.lastIndexOf(".");
if (pos == -1) return fullName;
else return fullName.substring(pos+1);
}
// END Debug method section
///////////////////////////////////////////////////////////////////////////////////
}