org.apache.hadoop.hive.ql.parse.ASTNode Maven / Gradle / Ivy
/*
* 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.apache.hadoop.hive.ql.parse;
import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hive.ql.lib.Node;
/**
*
*/
public class ASTNode extends CommonTree implements Node,Serializable {
private static final long serialVersionUID = 1L;
private transient StringBuilder astStr;
private transient ASTNodeOrigin origin;
private transient int startIndx = -1;
private transient int endIndx = -1;
private transient ASTNode rootNode;
private transient boolean isValidASTStr;
private transient boolean visited = false;
public ASTNode() {
}
/**
* Constructor.
*
* @param t
* Token for the CommonTree Node
*/
public ASTNode(Token t) {
super(t);
}
public ASTNode(ASTNode node) {
super(node);
this.origin = node.origin;
}
@Override
public Tree dupNode() {
return new ASTNode(this);
}
/*
* (non-Javadoc)
*
* @see org.apache.hadoop.hive.ql.lib.Node#getChildren()
*/
@Override
public ArrayList getChildren() {
if (super.getChildCount() == 0) {
return null;
}
ArrayList ret_vec = new ArrayList();
for (int i = 0; i < super.getChildCount(); ++i) {
ret_vec.add((Node) super.getChild(i));
}
return ret_vec;
}
/*
* (non-Javadoc)
*
* @see org.apache.hadoop.hive.ql.lib.Node#getName()
*/
@Override
public String getName() {
return String.valueOf(super.getToken().getType());
}
/**
* For every node in this subtree, make sure it's start/stop token's
* are set. Walk depth first, visit bottom up. Only updates nodes
* with at least one token index < 0.
*
* In contrast to the method in the parent class, this method is
* iterative.
*/
@Override
public void setUnknownTokenBoundaries() {
Deque stack1 = new ArrayDeque();
Deque stack2 = new ArrayDeque();
stack1.push(this);
while (!stack1.isEmpty()) {
ASTNode next = stack1.pop();
stack2.push(next);
if (next.children != null) {
for (int i = next.children.size() - 1; i >= 0 ; i--) {
stack1.push((ASTNode)next.children.get(i));
}
}
}
while (!stack2.isEmpty()) {
ASTNode next = stack2.pop();
if (next.children == null) {
if (next.startIndex < 0 || next.stopIndex < 0) {
next.startIndex = next.stopIndex = next.token.getTokenIndex();
}
} else if (next.startIndex >= 0 && next.stopIndex >= 0) {
continue;
} else if (next.children.size() > 0) {
ASTNode firstChild = (ASTNode)next.children.get(0);
ASTNode lastChild = (ASTNode)next.children.get(next.children.size()-1);
next.startIndex = firstChild.getTokenStartIndex();
next.stopIndex = lastChild.getTokenStopIndex();
}
}
}
/**
* @return information about the object from which this ASTNode originated, or
* null if this ASTNode was not expanded from an object reference
*/
public ASTNodeOrigin getOrigin() {
return origin;
}
/**
* Tag this ASTNode with information about the object from which this node
* originated.
*/
public void setOrigin(ASTNodeOrigin origin) {
this.origin = origin;
}
public String dump() {
StringBuilder sb = new StringBuilder("\n");
dump(sb);
return sb.toString();
}
private StringBuilder dump(StringBuilder sb) {
Deque stack = new ArrayDeque();
stack.push(this);
int tabLength = 0;
while (!stack.isEmpty()) {
ASTNode next = stack.peek();
if (!next.visited) {
sb.append(StringUtils.repeat(" ", tabLength * 3));
sb.append(next.toString());
sb.append("\n");
if (next.children != null) {
for (int i = next.children.size() - 1 ; i >= 0 ; i--) {
stack.push((ASTNode)next.children.get(i));
}
}
tabLength++;
next.visited = true;
} else {
tabLength--;
next.visited = false;
stack.pop();
}
}
return sb;
}
private void getRootNodeWithValidASTStr () {
if (rootNode != null && rootNode.parent == null &&
rootNode.hasValidMemoizedString()) {
return;
}
ASTNode retNode = this;
while (retNode.parent != null) {
retNode = (ASTNode) retNode.parent;
}
rootNode=retNode;
if (!rootNode.isValidASTStr) {
rootNode.astStr = new StringBuilder();
rootNode.toStringTree(rootNode);
rootNode.isValidASTStr = true;
}
return;
}
private boolean hasValidMemoizedString() {
return isValidASTStr && astStr != null;
}
private void resetRootInformation() {
// Reset the previously stored rootNode string
if (rootNode != null) {
rootNode.astStr = null;
rootNode.isValidASTStr = false;
}
}
private int getMemoizedStringLen() {
return astStr == null ? 0 : astStr.length();
}
private String getMemoizedSubString(int start, int end) {
return (astStr == null || start < 0 || end > astStr.length() || start >= end) ? null :
astStr.subSequence(start, end).toString();
}
private void addtoMemoizedString(String string) {
if (astStr == null) {
astStr = new StringBuilder();
}
astStr.append(string);
}
@Override
public void setParent(Tree t) {
super.setParent(t);
resetRootInformation();
}
@Override
public void addChild(Tree t) {
super.addChild(t);
resetRootInformation();
}
@Override
public void addChildren(List kids) {
super.addChildren(kids);
resetRootInformation();
}
@Override
public void setChild(int i, Tree t) {
super.setChild(i, t);
resetRootInformation();
}
@Override
public void insertChild(int i, Object t) {
super.insertChild(i, t);
resetRootInformation();
}
@Override
public Object deleteChild(int i) {
Object ret = super.deleteChild(i);
resetRootInformation();
return ret;
}
@Override
public void replaceChildren(int startChildIndex, int stopChildIndex, Object t) {
super.replaceChildren(startChildIndex, stopChildIndex, t);
resetRootInformation();
}
@Override
public String toStringTree() {
// The root might have changed because of tree modifications.
// Compute the new root for this tree and set the astStr.
getRootNodeWithValidASTStr();
// If rootNotModified is false, then startIndx and endIndx will be stale.
if (startIndx >= 0 && endIndx <= rootNode.getMemoizedStringLen()) {
return rootNode.getMemoizedSubString(startIndx, endIndx);
}
return toStringTree(rootNode);
}
private String toStringTree(ASTNode rootNode) {
Deque stack = new ArrayDeque();
stack.push(this);
while (!stack.isEmpty()) {
ASTNode next = stack.peek();
if (!next.visited) {
if (next.parent != null && next.parent.getChildCount() > 1 &&
next != next.parent.getChild(0)) {
rootNode.addtoMemoizedString(" ");
}
next.rootNode = rootNode;
next.startIndx = rootNode.getMemoizedStringLen();
// Leaf
if (next.children == null || next.children.size() == 0) {
String str = next.toString();
rootNode.addtoMemoizedString(next.getType() != HiveParser.StringLiteral ? str.toLowerCase() : str);
next.endIndx = rootNode.getMemoizedStringLen();
stack.pop();
continue;
}
if ( !next.isNil() ) {
rootNode.addtoMemoizedString("(");
String str = next.toString();
rootNode.addtoMemoizedString((next.getType() == HiveParser.StringLiteral || null == str) ? str : str.toLowerCase());
rootNode.addtoMemoizedString(" ");
}
if (next.children != null) {
for (int i = next.children.size() - 1 ; i >= 0 ; i--) {
stack.push((ASTNode)next.children.get(i));
}
}
next.visited = true;
} else {
if ( !next.isNil() ) {
rootNode.addtoMemoizedString(")");
}
next.endIndx = rootNode.getMemoizedStringLen();
next.visited = false;
stack.pop();
}
}
return rootNode.getMemoizedSubString(startIndx, endIndx);
}
}