org.apache.hadoop.hive.ql.parse.ASTNode.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hive.ql.parse.ASTNode.java

Source

/**
 * 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<Node> getChildren() {
        if (super.getChildCount() == 0) {
            return null;
        }

        ArrayList<Node> ret_vec = new ArrayList<Node>();
        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<ASTNode> stack1 = new ArrayDeque<ASTNode>();
        Deque<ASTNode> stack2 = new ArrayDeque<ASTNode>();
        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<ASTNode> stack = new ArrayDeque<ASTNode>();
        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<ASTNode> stack = new ArrayDeque<ASTNode>();
        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);
    }
}