de.monticore.utils.ASTNodes.java Source code

Java tutorial

Introduction

Here is the source code for de.monticore.utils.ASTNodes.java

Source

/*
 * ******************************************************************************
 * MontiCore Language Workbench
 * Copyright (c) 2015, MontiCore, All rights reserved.
 *
 * This project is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this project. If not, see <http://www.gnu.org/licenses/>.
 * ******************************************************************************
 */

package de.monticore.utils;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import de.monticore.ast.ASTNode;
import de.se_rwth.commons.Util;

import java.util.Collection;
import java.util.List;

/**
 * Helper class containing common operations concerning ASTNodes
 *
 * @author Sebastian Oberhoff
 */
public final class ASTNodes {

    private ASTNodes() {
        // noninstantiable
    }

    /**
     * Checks whether two ASTNodes are in a vertical relationship with each other with any number of
     * other nodes in between.
     * <p>
     * This operation is O(n), where n is the number of nodes contained in the subtree spanned by the
     * ancestor.
     *
     * @param ancestor  the node further up in the AST
     * @param successor the node further down in the AST
     * @return true if there exists a descending path from the ancestor to the successor
     */
    public static boolean areAncestorAndSuccessor(ASTNode ancestor, ASTNode successor) {
        Iterable<ASTNode> successors = Util.preOrder(ancestor, ASTNode::get_Children);
        return Iterables.any(successors, otherSuccessor -> otherSuccessor == successor);
    }

    /**
     * Calculates the list of nodes spanning a vertical path from ancestor node to successor.
     * <p>
     * The returned list will be empty if no path exists between ancestor and successor.
     * <p>
     * The returned list also contains both ancestor and successor if a path is indeed present.
     * <p>
     * This operation is O(n), where n is the number of nodes contained in the subtree spanned by
     * the ancestor.
     *
     * @param ancestor  the node at the top of the path
     * @param successor the node at the bottom of the path
     * @return the list of nodes from the ancestor to the successor, sorted from ancestor (first
     * element) to successor (last element)
     */
    public static List<ASTNode> getIntermediates(ASTNode ancestor, ASTNode successor) {
        ImmutableMap<ASTNode, ASTNode> childToParentMap = childToParentMap(ancestor);
        List<ASTNode> allAncestors = Util.listTillPredicate(successor, childToParentMap::get, node -> node != null);
        return Lists.reverse(allAncestors);
    }

    /**
     * Gathers a list of all successor nodes of an ASTNode with a specified type.
     *
     * @param ancestor the ancestor node of which successors with the specified type are to be
     *                 gathered
     * @param nodeType the type of successors to be gathered
     * @return the list of successors of the ancestor node with the specified type, ordered according
     * to a pre-order traversal
     */
    public static <T extends ASTNode> List<T> getSuccessors(ASTNode ancestor, Class<T> nodeType) {
        Iterable<ASTNode> successors = Util.preOrder(ancestor, ASTNode::get_Children);
        Iterable<T> successorsWithMatchingType = Iterables.filter(successors, nodeType);
        return Lists.newArrayList(successorsWithMatchingType);
    }

    /**
     * Gathers a list of all successor nodes of an ASTNode with a specified type.
     *
     * @param ancestor the ancestor node of which successors with the specified type are to be
     *                 gathered
     * @param nodeType the type of successors to be gathered
     * @return the list of successors of the ancestor node with the specified type, ordered according
     * to a pre-order traversal
     */
    public static List<ASTNode> getSuccessors(ASTNode ancestor, Collection<Class<? extends ASTNode>> types) {
        Iterable<ASTNode> successors = Util.preOrder(ancestor, ASTNode::get_Children);
        Iterable<ASTNode> successorsWithMatchingType = Iterables.filter(successors,
                successor -> types.contains(successor.getClass()));
        return Lists.newArrayList(successorsWithMatchingType);
    }

    /**
     * @param root the root of the subtree for which the map is to be created
     * @return an {@link ImmutableMap} from child-ASTNode to parent-ASTNode for all ASTNodes below the given root
     */
    public static ImmutableMap<ASTNode, ASTNode> childToParentMap(ASTNode root) {
        ImmutableMap.Builder<ASTNode, ASTNode> builder = ImmutableMap.builder();
        Util.preOrder(root, ASTNode::get_Children).stream().forEach(node -> {
            for (ASTNode child : node.get_Children()) {
                builder.put(child, node);
            }
        });
        return builder.build();
    }
}