de.monticore.utils.Link.java Source code

Java tutorial

Introduction

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

import javax.annotation.Nullable;

import de.monticore.ast.ASTNode;

import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

import de.se_rwth.commons.TreeUtil;
import de.se_rwth.commons.Util;

/**
 * Represents a link between two ASTNodes.
 * <p>
 * When writing transformations that translate from one AST to another, it is often cleaner not to
 * translate all information in a single operation. Splitting this translation process however
 * necessitates that sequentially executed translations always operate on the same source and target
 * nodes. For this purpose a Link provides a way for the program to "remember" which source nodes
 * are associated with which target nodes.
 * <p>
 * Going beyond that, Links also form a tree that mirrors the structure in both ASTs. This is based
 * on the assumption that the overall structure of both source and target AST will also be
 * equivalent.
 * 
 * @author Sebastian Oberhoff
 */
public final class Link<S extends ASTNode, T extends ASTNode> implements Iterable<Link<?, ?>> {

    private final S source;

    private final T target;

    private final Link<?, ?> parent;

    private final Set<Link<?, ?>> childLinks = new LinkedHashSet<Link<?, ?>>();

    public Link(S source, T target, @Nullable Link<?, ?> parent) {
        this.source = source;
        this.target = target;
        this.parent = parent;
        if (parent != null) {
            parent.addChildLink(this);
        }
    }

    private void addChildLink(Link<?, ?> childLink) {
        childLinks.add(childLink);
    }

    /**
     * @return the source node of this Link
     */
    public S source() {
        return source;
    }

    /**
     * @return the target node of this Link
     */
    public T target() {
        return target;
    }

    /**
     * @return the parent Link of this Link
     */
    public Link<?, ?> parent() {
        return parent;
    }

    /**
     * @return the topmost Link in the tree to which this Link belongs
     */
    public Link<?, ?> rootLink() {
        List<Link<?, ?>> parents = Util.listTillNull(this, Link::parent);
        return Iterables.getLast(parents);
    }

    @Override
    public Iterator<Link<?, ?>> iterator() {
        Iterable<Link<?, ?>> subtree = TreeUtil.preOrder(this, link -> link.childLinks);
        return subtree.iterator();
    }

    /**
     * Looks up all Links in the subtree spanned by this Link by type of source and target. You can
     * use super classes like 'ASTNode.class' if you want to filter more loosely.
     * 
     * @param sourceType the class of the source node
     * @param targetType the class of the target node
     * @return the set of all Links with the specified source and target types
     */
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
    public <O extends ASTNode, D extends ASTNode> Set<Link<O, D>> getLinks(Class<O> sourceType,
            Class<D> targetType) {

        Set matchingLinks = Sets.newLinkedHashSet(Iterables.filter(this,
                link -> sourceType.isInstance(link.source) && targetType.isInstance(link.target)));

        return matchingLinks;
    }
}