blob: 4b708713a7b067399ecbc98a3c63c3ef5f532006 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtp2qvts;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.impl.VariableNodeImpl;
public class RegionMerger extends AbstractVisitor<@Nullable Visitable>
{
public static @NonNull MappingRegion createMergedRegion(@NonNull MappingRegion primaryRegion, @NonNull MappingRegion secondaryRegion, @NonNull Map<@NonNull Node, @NonNull Node> secondaryNode2primaryNode) {
RegionMerger regionMerger = new RegionMerger(primaryRegion, secondaryRegion, secondaryNode2primaryNode);
Visitable mergedRegion = secondaryRegion.accept(regionMerger);
assert mergedRegion != null;
return (MappingRegion) mergedRegion;
}
protected final @NonNull MappingRegion primaryRegion;
protected final @NonNull MappingRegion secondaryRegion;
protected final @NonNull Map<@NonNull Node, @NonNull Node> secondaryNode2primaryNode;
protected final @NonNull MappingRegion mergedRegion;
protected final @NonNull Map<@NonNull Node, @NonNull Node> oldNode2mergedNode = new HashMap<>();
protected final @NonNull Map<@NonNull Edge, @NonNull List<@NonNull Edge>> oldEdge2oldEdges = new HashMap<>();
private final @NonNull Map<@NonNull Edge, @NonNull Edge> debugOldEdge2mergedEdge = new HashMap<>();
protected RegionMerger(@NonNull MappingRegion primaryRegion, @NonNull MappingRegion secondaryRegion, @NonNull Map<@NonNull Node, @NonNull Node> secondaryNode2primaryNode) {
this.primaryRegion = primaryRegion;
this.secondaryRegion = secondaryRegion;
this.secondaryNode2primaryNode = secondaryNode2primaryNode;
this.mergedRegion = new MergedMappingRegion(primaryRegion, secondaryRegion);
}
protected void accumulateEdge(@NonNull Map<@NonNull Node, @NonNull Map<@NonNull Node, @NonNull List<@NonNull List<@NonNull Edge>>>> mergedSourceNode2mergedTargetNode2listOfOldEdges, @NonNull Edge oldEdge) {
// List<@NonNull Edge> oldOldEdges2 = oldEdge2oldEdges.get(oldEdge);
// assert oldOldEdges2 == null;
Node mergedSourceNode = oldNode2mergedNode.get(oldEdge.getSource());
Node mergedTargetNode = oldNode2mergedNode.get(oldEdge.getTarget());
assert (mergedSourceNode != null) && (mergedTargetNode != null);
Map<@NonNull Node, @NonNull List<@NonNull List<@NonNull Edge>>> mergedTargetNode2listOfOldEdges = mergedSourceNode2mergedTargetNode2listOfOldEdges.get(mergedSourceNode);
if (mergedTargetNode2listOfOldEdges == null) {
mergedTargetNode2listOfOldEdges = new HashMap<>();
mergedSourceNode2mergedTargetNode2listOfOldEdges.put(mergedSourceNode, mergedTargetNode2listOfOldEdges);
}
List<@NonNull List<@NonNull Edge>> listOfOldEdges = mergedTargetNode2listOfOldEdges.get(mergedTargetNode);
if (listOfOldEdges == null) {
listOfOldEdges = new ArrayList<>();
mergedTargetNode2listOfOldEdges.put(mergedTargetNode, listOfOldEdges);
}
List<@NonNull Edge> matchingOldEdges = null;
for (@NonNull List<@NonNull Edge> oldEdges : listOfOldEdges) {
if (sameEdge(oldEdge, oldEdges)) {
matchingOldEdges = oldEdges;
break;
}
}
if (matchingOldEdges == null) {
matchingOldEdges = new ArrayList<>();
listOfOldEdges.add(matchingOldEdges);
}
matchingOldEdges.add(oldEdge);
List<@NonNull Edge> oldOldEdges = oldEdge2oldEdges.put(oldEdge, matchingOldEdges);
assert oldOldEdges == null;
}
private void checkEdges(@NonNull Region oldRegion) {
for (@NonNull Edge oldEdge : oldRegion.getEdges()) {
assert oldEdge.getRegion() == oldRegion;
if (!oldEdge.isRecursion() && !oldEdge.isSecondary()) { // FIXME Remove this irregularity
List<@NonNull Edge> oldEdges = oldEdge2oldEdges.get(oldEdge);
assert oldEdges != null;
assert oldEdges.contains(oldEdge);
Edge mergedEdge = debugOldEdge2mergedEdge.get(oldEdge);
assert mergedEdge != null;
assert mergedEdge.getRegion() == mergedRegion;
}
}
}
private void checkNodes(@NonNull Region oldRegion) {
for (@NonNull Node oldNode : oldRegion.getNodes()) {
assert oldNode.getRegion() == oldRegion;
Node mergedNode = oldNode2mergedNode.get(oldNode);
assert mergedNode != null;
assert mergedNode.getRegion() == mergedRegion;
}
}
protected void createMergedEdge(@NonNull Iterable<@NonNull Edge> oldEdges) {
Edge mergedEdge = null;
for (@NonNull Edge oldEdge : oldEdges) {
mergedEdge = (Edge)oldEdge.accept(this);
break;
}
if (mergedEdge != null) {
for (@NonNull Edge oldEdge : oldEdges) {
debugOldEdge2mergedEdge.put(oldEdge, mergedEdge);
}
}
}
private boolean sameEdge(@NonNull Edge newEdge, @NonNull Iterable<@NonNull Edge> oldEdges) {
if (newEdge instanceof NavigableEdge) {
Property newProperty = ((NavigableEdge)newEdge).getProperty();
for (@NonNull Edge oldEdge : oldEdges) {
if (oldEdge instanceof NavigableEdge) {
Property oldProperty = ((NavigableEdge)oldEdge).getProperty();
if (oldProperty == newProperty) {
return true;
}
}
}
}
else {
Class<? extends @NonNull Edge> newClass = newEdge.getClass();
for (@NonNull Edge oldEdge : oldEdges) {
Class<? extends @NonNull Edge> oldClass = oldEdge.getClass();
if (oldClass == newClass) {
return true;
}
}
}
return false;
}
@Override
public @NonNull Visitable visitEdge(@NonNull Edge edge) {
Node mergedSourceNode = oldNode2mergedNode.get(edge.getSource());
Node mergedTargetNode = oldNode2mergedNode.get(edge.getTarget());
assert (mergedSourceNode != null) && (mergedTargetNode != null);
EdgeRole edgeRole = null;
List<@NonNull Edge> oldEdges = oldEdge2oldEdges.get(edge);
assert oldEdges != null;
for (@NonNull Edge oldEdge : oldEdges) {
EdgeRole edgeRole2 = oldEdge.getEdgeRole();
edgeRole = edgeRole != null ? RegionUtil.mergeToMoreKnownPhase(edgeRole, edgeRole2) : edgeRole2;
}
assert edgeRole != null;
return edge.createEdge(edgeRole, mergedSourceNode, mergedTargetNode);
}
@Override
public @NonNull MappingRegion visitMappingRegion(@NonNull MappingRegion mappingRegion) {
Set<@NonNull Node> toBeMergedNodes = new HashSet<>(primaryRegion.getNodes());
toBeMergedNodes.removeAll(secondaryNode2primaryNode.values());
toBeMergedNodes.addAll(secondaryRegion.getNodes());
for (@NonNull Node toBeMergedNode : toBeMergedNodes) {
toBeMergedNode.accept(this);
}
//
//
//
Map<@NonNull Node, @NonNull Map<@NonNull Node, @NonNull List<@NonNull List<@NonNull Edge>>>> mergedSourceNode2mergedTargetNode2listOfOldEdges = new HashMap<>();
for (@NonNull Edge oldEdge : primaryRegion.getEdges()) {
if (!oldEdge.isRecursion()) { // FIXME Remove this irregularity
accumulateEdge(mergedSourceNode2mergedTargetNode2listOfOldEdges, oldEdge);
}
}
for (@NonNull Edge oldEdge : secondaryRegion.getEdges()) {
if (!oldEdge.isRecursion()) { // FIXME Remove this irregularity
accumulateEdge(mergedSourceNode2mergedTargetNode2listOfOldEdges, oldEdge);
}
}
for (@NonNull Map<@NonNull Node, @NonNull List<@NonNull List<@NonNull Edge>>> mergedTargetNode2listOfOldEdges : mergedSourceNode2mergedTargetNode2listOfOldEdges.values()) {
for (@NonNull List<@NonNull List<@NonNull Edge>> listOfOldEdges : mergedTargetNode2listOfOldEdges.values()) {
assert listOfOldEdges != null;
for (@NonNull List<@NonNull Edge> oldEdges : listOfOldEdges) {
createMergedEdge(oldEdges);
}
}
}
checkNodes(primaryRegion);
checkNodes(secondaryRegion);
checkEdges(primaryRegion);
checkEdges(secondaryRegion);
return mergedRegion;
}
@Override
public @Nullable Visitable visitNavigableEdge(@NonNull NavigableEdge navigationEdge) {
if (navigationEdge.isSecondary()) {
return null;
}
Node mergedSourceNode = oldNode2mergedNode.get(navigationEdge.getSource());
Node mergedTargetNode = oldNode2mergedNode.get(navigationEdge.getTarget());
assert (mergedSourceNode != null) && (mergedTargetNode != null);
EdgeRole edgeRole = null;
List<@NonNull Edge> oldEdges = oldEdge2oldEdges.get(navigationEdge);
assert oldEdges != null;
for (@NonNull Edge oldEdge : oldEdges) {
EdgeRole edgeRole2 = oldEdge.getEdgeRole();
edgeRole = edgeRole != null ? RegionUtil.mergeToMoreKnownPhase(edgeRole, edgeRole2) : edgeRole2;
}
assert edgeRole != null;
return navigationEdge.createEdge(edgeRole, mergedSourceNode, mergedTargetNode);
}
@Override
public @NonNull Node visitNode(@NonNull Node node) {
NodeRole nodeRole = node.getNodeRole();
Node primaryNode = secondaryNode2primaryNode.get(node);
if (primaryNode != null) {
nodeRole = nodeRole.merge(primaryNode.getNodeRole());
}
Node mergedNode = node.createNode(nodeRole, mergedRegion);
oldNode2mergedNode.put(node, mergedNode);
for (@NonNull TypedElement typedElement : node.getTypedElements()) {
mergedNode.addTypedElement(typedElement);
}
if (primaryNode != null) {
oldNode2mergedNode.put(primaryNode, mergedNode);
for (@NonNull TypedElement typedElement : primaryNode.getTypedElements()) {
mergedNode.addTypedElement(typedElement);
}
}
return mergedNode;
}
@Override
public @NonNull Node visitVariableNode(@NonNull VariableNodeImpl variableNode) {
NodeRole nodeRole = variableNode.getNodeRole();
Node primaryNode = secondaryNode2primaryNode.get(variableNode);
if (primaryNode != null) {
nodeRole = nodeRole.merge(primaryNode.getNodeRole());
}
Node mergedNode = variableNode.createNode(nodeRole, mergedRegion);
oldNode2mergedNode.put(variableNode, mergedNode);
for (@NonNull TypedElement typedElement : variableNode.getTypedElements()) {
mergedNode.addTypedElement(typedElement);
}
if (primaryNode != null) {
oldNode2mergedNode.put(primaryNode, mergedNode);
for (@NonNull TypedElement typedElement : primaryNode.getTypedElements()) {
mergedNode.addTypedElement(typedElement);
}
}
return mergedNode;
}
}