de.monticore.utils.NodeWithParent.java Source code

Java tutorial

Introduction

Here is the source code for de.monticore.utils.NodeWithParent.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 java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import de.monticore.ast.ASTNode;

import java.util.Optional;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;

public class NodeWithParent<T extends ASTNode> extends ForwardingASTNode<T> implements Iterable<NodeWithParent<?>> {

    private final T astNode;

    private final NodeWithParent<? extends ASTNode> parent;

    private final Set<NodeWithParent<?>> children = new LinkedHashSet<>();

    public NodeWithParent(T astNode) {
        this.astNode = astNode;
        this.parent = null;
        for (ASTNode childNode : astNode.get_Children()) {
            this.children.add(new NodeWithParent<>(childNode, this));
        }
    }

    private NodeWithParent(T astNode, NodeWithParent<?> parent) {
        this.astNode = astNode;
        this.parent = parent;
        for (ASTNode childNode : astNode.get_Children()) {
            this.children.add(new NodeWithParent<>(childNode, this));
        }
    }

    @Override
    public T delegate() {
        return astNode;
    }

    @Override
    public Iterator<NodeWithParent<?>> iterator() {
        Iterator<NodeWithParent<?>> childIterator = Iterables.concat(children).iterator();
        return Iterators.concat(Iterators.singletonIterator(this), childIterator);
    }

    public Optional<NodeWithParent<?>> getParentNodeWithParent() {
        return Optional.ofNullable(parent);
    }

    public Set<NodeWithParent<?>> getChildNodesWithParent() {
        return children;
    }

    public List<NodeWithParent<?>> getAncestorNodesWithParent() {
        List<NodeWithParent<?>> ancestors = new ArrayList<>();

        for (NodeWithParent<?> ancestor = this; ancestor != null; ancestor = ancestor.getParentNodeWithParent()
                .orElse(null)) {
            ancestors.add(ancestor);
        }

        return ancestors;
    }

    /**
     * This method is a more general and typed version of {@link #getParentNodeWithParent()}. The set
     * of examined ancestors includes this NodeWithParent.
     * 
     * @param nodeType the type of ancestor to be returned
     * @return the closest ancestor of the specified type. The Optional wrapper should serve as a
     * reminder that such an ancestor may not necessarily exist.
     */
    // This method requires raw types since the generic type of any NodeWithParent is erased at
    // runtime and the compiler can't confirm the correctness of the runtime check used in this
    // method.
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <C extends ASTNode> Optional<NodeWithParent<C>> getClosestAncestor(Class<C> nodeType) {
        Optional closestAncestor = Optional.empty();

        for (NodeWithParent<?> ancestor : getAncestorNodesWithParent()) {
            if (nodeType.isInstance(ancestor.delegate())) {
                closestAncestor = Optional.of(ancestor);
                break;
            }
        }

        return closestAncestor;
    }

    /**
     * Examines the entire subtree below and including this NodeWithParent.
     * 
     * @param nodeType the type of successor to be returned
     * @return the set of all successors of the specified type
     */
    // This method requires raw types since the generic type of any NodeWithParent is erased at
    // runtime and the compiler can't confirm the correctness of the runtime check used in this
    // method.
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <C extends ASTNode> Set<NodeWithParent<C>> getSuccessors(Class<C> nodeType) {

        Set filteredNodesWithParent = Sets
                .newLinkedHashSet(Iterables.filter(this, node -> nodeType.isInstance(node.astNode)));

        return filteredNodesWithParent;
    }

}