blob: eb8ef23c171fd9b42d794631010298bb4e95939e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 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.qvts2qvti;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.AnyType;
import org.eclipse.ocl.pivot.CollectionItem;
import org.eclipse.ocl.pivot.CollectionLiteralExp;
import org.eclipse.ocl.pivot.CollectionLiteralPart;
import org.eclipse.ocl.pivot.CollectionRange;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.IfExp;
import org.eclipse.ocl.pivot.InvalidType;
import org.eclipse.ocl.pivot.IterateExp;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.IteratorExp;
import org.eclipse.ocl.pivot.MapLiteralExp;
import org.eclipse.ocl.pivot.MapLiteralPart;
import org.eclipse.ocl.pivot.MapType;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.OppositePropertyCallExp;
import org.eclipse.ocl.pivot.PrimitiveLiteralExp;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.PropertyCallExp;
import org.eclipse.ocl.pivot.ShadowExp;
import org.eclipse.ocl.pivot.ShadowPart;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.TupleLiteralExp;
import org.eclipse.ocl.pivot.TupleLiteralPart;
import org.eclipse.ocl.pivot.TupleType;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypeExp;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.VoidType;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.util.Visitable;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.ClassDatumAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Edge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.EdgeRole;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NavigationEdge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NodeConnection;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Region;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.RegionUtil;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.SchedulerConstants;
import org.eclipse.qvtd.pivot.qvtbase.Domain;
import org.eclipse.qvtd.pivot.qvtbase.Function;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.QVTbaseFactory;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtcorebase.Area;
import org.eclipse.qvtd.pivot.qvtcorebase.Assignment;
import org.eclipse.qvtd.pivot.qvtcorebase.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcorebase.GuardPattern;
import org.eclipse.qvtd.pivot.qvtcorebase.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcorebase.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcorebase.VariableAssignment;
import org.eclipse.qvtd.pivot.qvtcorebase.analysis.DomainUsage;
import org.eclipse.qvtd.pivot.qvtcorebase.utilities.AssignmentComparator;
import org.eclipse.qvtd.pivot.qvtimperative.ConnectionVariable;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeArea;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeBottomPattern;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeDomain;
import org.eclipse.qvtd.pivot.qvtimperative.MappingCallBinding;
import org.eclipse.qvtd.pivot.qvtimperative.MappingStatement;
import org.eclipse.qvtd.pivot.qvtimperative.util.AbstractExtendingQVTimperativeVisitor;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
import com.google.common.collect.Iterables;
public class BasicRegion2Mapping extends AbstractRegion2Mapping
{
private static final class DomainNameComparator implements Comparator<@NonNull Domain>
{
public static final @NonNull DomainNameComparator INSTANCE = new DomainNameComparator();
@Override
public int compare(@NonNull Domain o1, @NonNull Domain o2) {
TypedModel t1 = o1.getTypedModel();
TypedModel t2 = o2.getTypedModel();
String n1 = t1 != null ? t1.getName() : null;
String n2 = t2 != null ? t2.getName() : null;
return ClassUtil.safeCompareTo(n1, n2);
}
}
private class ExpressionCreator extends AbstractExtendingQVTimperativeVisitor<@NonNull OCLExpression, @NonNull BasicRegion2Mapping>
{
protected final @NonNull Set<@NonNull Node> multiAccessedNodes = new HashSet<@NonNull Node>();
protected final @NonNull Set<@NonNull Node> conditionalNodes = new HashSet<@NonNull Node>();
public ExpressionCreator() {
super(BasicRegion2Mapping.this);
analyzeExpressions(multiAccessedNodes, conditionalNodes);
}
/**
* Compute the nodes that are only evaluated if a run-time if-condition is satisfied, and the nodes that are always accessed more than once.
*/
private void analyzeExpressions(@NonNull Set<Node> multiAccessedNodes, @NonNull Set<Node> conditionalNodes) {
Set<@NonNull Node> unconditionalNodes = new HashSet<@NonNull Node>();
for (@NonNull Edge edge : region.getRealizedEdges()) {
analyzeIncomingPath(edge.getTarget(), unconditionalNodes, conditionalNodes, false);
}
conditionalNodes.removeAll(unconditionalNodes);
// if (conditionalNodes.size() > 0) {
// System.out.println("Conditional nodes for " + this);
// for (Node conditionalNode : conditionalNodes) {
// System.out.println(" " + conditionalNode);
// }
// }
for (@NonNull Node node : unconditionalNodes) {
int accesses = 0;
for (@NonNull Edge outgoingEdge : node.getOutgoingEdges()) {
if (outgoingEdge.isNavigation() || outgoingEdge.isComputation()) {
accesses++;
}
}
if (accesses > 1) {
multiAccessedNodes.add(node);
}
}
// if (multiAccessedNodes.size() > 0) {
// System.out.println("multi-accessed nodes for " + this);
// for (Node multiAccessedNode : multiAccessedNodes) {
// System.out.println(" " + multiAccessedNode);
// }
// }
}
private void analyzeIncomingPath(@NonNull Node node, @NonNull Set<Node> unconditionalNodes, @NonNull Set<Node> conditionalNodes, boolean isConditional) {
if ((isConditional ? conditionalNodes : unconditionalNodes).add(node)) {
boolean isIf = isIfExp(node);
for (@NonNull Edge edge : node.getIncomingEdges()) {
if (edge.isComputation()) {
boolean isIfThenOrElse = isIf && ("then".equals(edge.getName()) || "else".equals(edge.getName()));
analyzeIncomingPath(edge.getSource(), unconditionalNodes, conditionalNodes, isConditional || isIfThenOrElse);
}
else if (edge.isNavigation()) {
analyzeIncomingPath(edge.getSource(), unconditionalNodes, conditionalNodes, isConditional);
}
}
return;
}
}
protected @NonNull OCLExpression create(/*@NonNull*/ Node node) {
if (node.isNull()) {
return helper.createNullLiteralExp();
}
Variable theVariable = node2variable.get(node);
if (theVariable == null) {
TypedElement oldTypedElement = node.getTypedElements().iterator().next();
assert oldTypedElement != null;
OCLExpression initExpression = oldTypedElement.accept(this);
assert initExpression != null;
// Type type = newExpression.getType();
// assert type != null;
// theVariable = PivotUtil.createVariable(getSafeName(node), type, true, newExpression);
// mapping.getBottomPattern().getVariable().add(theVariable);
// node2variable.put(node, theVariable);
if ((initExpression instanceof PrimitiveLiteralExp) || hasRealizedVariableReference(initExpression) || conditionalNodes.contains(node)) {
return initExpression;
}
theVariable = createBottomVariable(node, initExpression);
}
return PivotUtil.createVariableExp(theVariable);
}
private @Nullable OCLExpression create(@Nullable OCLExpression oldTypedElement) {
if (oldTypedElement == null) {
return null;
}
Node node = context.getNode(oldTypedElement);
if (node == null) {
node = context.getNode(oldTypedElement); // FIXME debugging
}
if (node != null) {
return create(node);
}
else {
return oldTypedElement.accept(this);
}
}
private @NonNull List<@NonNull OCLExpression> createAll(@NonNull List<@NonNull OCLExpression> oldTypedElements) {
List<@NonNull OCLExpression> newTypedElements = new ArrayList<@NonNull OCLExpression>(oldTypedElements.size());
for (@NonNull OCLExpression oldTypedElement : oldTypedElements) {
OCLExpression newTypedElement = create(oldTypedElement);
assert newTypedElement != null;
newTypedElements.add(newTypedElement);
}
return newTypedElements;
}
private @NonNull OCLExpression createNonNull(@Nullable OCLExpression oldTypedElement) {
assert oldTypedElement != null;
Node node = context.getNode(oldTypedElement);
if (node == null) {
node = context.getNode(oldTypedElement); // FIXME debugging
}
return create(node);
}
private @NonNull List<@NonNull Variable> createVariables(@NonNull List<@NonNull Variable> oldVariables) {
List<@NonNull Variable> newVariables = new ArrayList<@NonNull Variable>(oldVariables.size());
for (@NonNull Variable oldVariable : oldVariables) {
Variable newVariable = createVariable(oldVariable);
newVariables.add(newVariable);
}
return newVariables;
}
private @NonNull Variable createVariable(@NonNull Variable oldVariable) {
String name = oldVariable.getName();
assert name != null;
Type type = oldVariable.getType();
assert type != null;
Variable newVariable = PivotUtil.createVariable(name, type, oldVariable.isIsRequired(), create(oldVariable.getOwnedInit()));
Node variableNode = getNode(oldVariable);
if (variableNode != null) {
node2variable.put(variableNode, newVariable);
}
return newVariable;
}
@Override
public String toString() {
return getClass().getSimpleName() + " " + region;
}
@Override
public @NonNull OCLExpression visiting(@NonNull Visitable visitable) {
throw new UnsupportedOperationException(getClass().getSimpleName() + ": " + visitable.getClass().getSimpleName());
}
public @Nullable OCLExpression getExpression(@NonNull Node node) {
if (node.isNull()) {
return helper.createNullLiteralExp();
}
Variable variable = node2variable.get(node);
if (variable != null) {
return PivotUtil.createVariableExp(variable);
}
for (@NonNull Edge edge : node.getArgumentEdges()) {
Node expNode = edge.getSource();
// TypedElement oldTypedElement = expNode.getTypedElements().iterator().next();
// assert oldTypedElement != null;
OCLExpression clonedElement = create(expNode);
// assert clonedNode != null;
// TypedElement typedElement = clonedNode.getTypedElements().iterator().next();
if (clonedElement instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)clonedElement).getReferredVariable();
if (referredVariable instanceof Variable) {
node2variable.put(node, (Variable) referredVariable);
}
}
return clonedElement;
}
for (@NonNull Edge edge : node.getIncomingEdges()) {
EdgeRole edgeRole = edge.getEdgeRole();
if (edgeRole.isNavigation()) {
if (edgeRole.isLoaded()) {
OCLExpression source = getExpression(edge.getSource());
if (source != null) {
return PivotUtil.createNavigationCallExp(source, ((NavigationEdge)edge).getProperty());
}
}
else if (edgeRole.isPredicated()) {
OCLExpression source = create(edge.getSource());
return PivotUtil.createNavigationCallExp(source, ((NavigationEdge)edge).getProperty());
}
}
}
return null;
}
private boolean hasRealizedVariableReference(@NonNull OCLExpression oclExpression) {
for (TreeIterator<EObject> tit = oclExpression.eAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof VariableExp) {
if (((VariableExp)eObject).getReferredVariable() instanceof RealizedVariable) {
return true;
}
}
}
return false;
}
// public boolean isConditional(@NonNull Node node) {
// return conditionalNodes.contains(node);
// }
@Override
public @NonNull OCLExpression visitCollectionLiteralExp(@NonNull CollectionLiteralExp pCollectionLiteralExp) {
List<@NonNull CollectionLiteralPart> clonedParts = new ArrayList<@NonNull CollectionLiteralPart>();
for (@NonNull CollectionLiteralPart pPart : ClassUtil.nullFree(pCollectionLiteralExp.getOwnedParts())) {
if (pPart instanceof CollectionItem) {
OCLExpression item = createNonNull(((CollectionItem)pPart).getOwnedItem());
clonedParts.add(helper.createCollectionItem(item));
}
else {
CollectionRange pCollectionRange = (CollectionRange)pPart;
OCLExpression first = createNonNull(pCollectionRange.getOwnedFirst());
OCLExpression last = createNonNull(pCollectionRange.getOwnedLast());
clonedParts.add(helper.createCollectionRange(first, last));
}
}
CollectionType collectionType = (CollectionType)pCollectionLiteralExp.getType();
assert collectionType != null;
return helper.createCollectionLiteralExp(collectionType, clonedParts);
}
@Override
public @NonNull OCLExpression visitIfExp(@NonNull IfExp pIfExp) {
PivotMetamodelManager metamodelManager = (PivotMetamodelManager)visitor.getMetamodelManager();
return metamodelManager.createIfExp(createNonNull(pIfExp.getOwnedCondition()),
inlineExpressionCreator.createNonNull(pIfExp.getOwnedThen()),
inlineExpressionCreator.createNonNull(pIfExp.getOwnedElse()));
}
@Override
public @NonNull OCLExpression visitIterateExp(@NonNull IterateExp pIterateExp) {
OCLExpression iSource = create(pIterateExp.getOwnedSource());
assert iSource != null;
List<@NonNull ? extends Variable> iIterators = createVariables(ClassUtil.nullFree(pIterateExp.getOwnedIterators()));
Variable result = createVariable(ClassUtil.nonNull(pIterateExp.getOwnedResult()));
Iteration referredIteration = (Iteration) visitor.create(pIterateExp.getReferredIteration());
assert referredIteration != null;
OCLExpression iBody = inlineExpressionCreator.create(pIterateExp.getOwnedBody());
assert iBody != null;
return helper.createIterateExp(iSource, referredIteration, iIterators, result, iBody);
}
@Override
public @NonNull OCLExpression visitIteratorExp(@NonNull IteratorExp pIteratorExp) {
OCLExpression iSource = create(pIteratorExp.getOwnedSource());
assert iSource != null;
List<@NonNull ? extends Variable> iIterators = createVariables(ClassUtil.nullFree(pIteratorExp.getOwnedIterators()));
Iteration referredIteration = (Iteration) visitor.create(pIteratorExp.getReferredIteration());
assert referredIteration != null;
OCLExpression iBody = inlineExpressionCreator.create(pIteratorExp.getOwnedBody());
assert iBody != null;
return helper.createIteratorExp(iSource, referredIteration, iIterators, iBody);
}
@Override
public @NonNull OCLExpression visitMapLiteralExp(@NonNull MapLiteralExp pMapLiteralExp) {
List<@NonNull MapLiteralPart> clonedParts = new ArrayList<@NonNull MapLiteralPart>();
for (@NonNull MapLiteralPart pPart : ClassUtil.nullFree(pMapLiteralExp.getOwnedParts())) {
OCLExpression key = createNonNull(pPart.getOwnedKey());
OCLExpression value = createNonNull(pPart.getOwnedValue());
clonedParts.add(helper.createMapLiteralPart(key, value));
}
MapType mapType = (MapType)pMapLiteralExp.getType();
assert mapType != null;
return helper.createMapLiteralExp(mapType, clonedParts);
}
@Override
public @NonNull OCLExpression visitOperationCallExp(@NonNull OperationCallExp pOperationCallExp) {
OCLExpression iSource = create(pOperationCallExp.getOwnedSource());
List<@NonNull OCLExpression> iArguments = createAll(ClassUtil.nullFree(pOperationCallExp.getOwnedArguments()));
Operation referredOperation = visitor.create(pOperationCallExp.getReferredOperation());
assert referredOperation != null;
if ((iSource == null) && (referredOperation instanceof Function)) {
SchedulerConstants scheduler = getRegion().getSuperRegion().getSchedulerConstants();
StandardLibrary standardLibrary = scheduler.getStandardLibrary();
Variable thisVariable = QVTbaseUtil.getContextVariable(standardLibrary, visitor.getTransformation());
iSource = PivotUtil.createVariableExp(thisVariable);
}
return helper.createOperationCallExp(iSource, referredOperation, iArguments);
}
@Override
public @NonNull OCLExpression visitOppositePropertyCallExp(@NonNull OppositePropertyCallExp pOppositePropertyCallExp) {
OCLExpression iSource = createNonNull(pOppositePropertyCallExp.getOwnedSource());
Property referredProperty = pOppositePropertyCallExp.getReferredProperty();
assert referredProperty != null;
return PivotUtil.createNavigationCallExp(iSource, referredProperty);
}
@Override
public @NonNull OCLExpression visitPrimitiveLiteralExp(@NonNull PrimitiveLiteralExp pPrimitiveLiteralExp) {
return EcoreUtil.copy(pPrimitiveLiteralExp);
}
@Override
public @NonNull OCLExpression visitPropertyCallExp(@NonNull PropertyCallExp pPropertyCallExp) {
OCLExpression iSource = createNonNull(pPropertyCallExp.getOwnedSource());
Property referredProperty = pPropertyCallExp.getReferredProperty();
assert referredProperty != null;
assert referredProperty.eContainer() != null;
return helper.createNavigationCallExp(iSource, referredProperty);
}
@Override
public @NonNull OCLExpression visitShadowExp(@NonNull ShadowExp pShadowExp) {
List<@NonNull ShadowPart> clonedParts = new ArrayList<@NonNull ShadowPart>();
for (@NonNull ShadowPart pPart : ClassUtil.nullFree(pShadowExp.getOwnedParts())) {
OCLExpression init = createNonNull(pPart.getOwnedInit());
String name = pPart.getName();
Type type = pPart.getType();
assert (name != null) && (type != null);
Property referredProperty = pPart.getReferredProperty();
assert referredProperty != null;
clonedParts.add(helper.createShadowPart(referredProperty, init));
}
org.eclipse.ocl.pivot.Class shadowType = pShadowExp.getType();
assert shadowType != null;
return helper.createShadowExp(shadowType, clonedParts);
}
@Override
public @NonNull OCLExpression visitTupleLiteralExp(@NonNull TupleLiteralExp pTupleLiteralExp) {
List<@NonNull TupleLiteralPart> clonedParts = new ArrayList<@NonNull TupleLiteralPart>();
for (@NonNull TupleLiteralPart pPart : ClassUtil.nullFree(pTupleLiteralExp.getOwnedParts())) {
OCLExpression init = createNonNull(pPart.getOwnedInit());
String name = pPart.getName();
Type type = pPart.getType();
assert (name != null) && (type != null);
clonedParts.add(helper.createTupleLiteralPart(name, type, pPart.isIsRequired(), init));
}
TupleType tupleType = (TupleType)pTupleLiteralExp.getType();
assert tupleType != null;
return helper.createTupleLiteralExp(tupleType, clonedParts);
}
@Override
public @NonNull OCLExpression visitTypeExp(@NonNull TypeExp pTypeExp) {
Type referredType = pTypeExp.getReferredType();
assert referredType != null;
return helper.createTypeExp(referredType);
}
@Override
public @NonNull OCLExpression visitVariableExp(@NonNull VariableExp pVariableExp) {
VariableDeclaration pVariable = pVariableExp.getReferredVariable();
Node node = getNode(pVariable);
if (node == null) {
SchedulerConstants scheduler = getRegion().getSuperRegion().getSchedulerConstants();
StandardLibrary standardLibrary = scheduler.getStandardLibrary();
Transformation pTransformation = QVTbaseUtil.getContainingTransformation(pVariableExp);
if (pTransformation != null) {
Variable pThisVariable = QVTbaseUtil.getContextVariable(standardLibrary, pTransformation);
if (pVariableExp.getReferredVariable() == pThisVariable) {
Variable iThisVariable = QVTbaseUtil.getContextVariable(standardLibrary, visitor.getTransformation());
return PivotUtil.createVariableExp(iThisVariable);
}
}
}
if (node != null) {
Variable iVariable = getVariable(node);
assert iVariable != null;
return PivotUtil.createVariableExp(iVariable);
}
else {
System.err.println("Creating unexpected variable for " + pVariable + " in " + region);
BottomPattern bottomPattern = mapping.getBottomPattern();
assert bottomPattern != null;
Type variableType = pVariable.getType();
assert variableType != null;
String safeName = getSafeName(ClassUtil.nonNullState(pVariable.getName()));
Variable iVariable = PivotUtil.createVariable(safeName, variableType, pVariable.isIsRequired(), null);
bottomPattern.getVariable().add(iVariable);
// Variable oldVariable = node2variable.put(node, iVariable);
// assert oldVariable == null;
return PivotUtil.createVariableExp(iVariable);
}
}
}
private class InlineExpressionCreator extends ExpressionCreator
{
@Override
public @NonNull OCLExpression create(/*@NonNull*/ Node node) {
if (node.isNull()) {
return helper.createNullLiteralExp();
}
Variable theVariable = node2variable.get(node);
if (theVariable == null) {
TypedElement oldTypedElement = node.getTypedElements().iterator().next();
assert oldTypedElement != null;
if ((oldTypedElement instanceof Variable) && (((Variable)oldTypedElement).getOwnedInit() == null)) {
// for (@NonNull Edge edge : node.getIncomingEdges()) {
// if (edge.isArgument() || edge.isCast()) {
theVariable = createBottomVariable(node, null);
// break;
// }
// }
}
else {
return oldTypedElement.accept(this);
}
assert theVariable != null;
}
return PivotUtil.createVariableExp(theVariable);
}
}
/**
* The selected head from each head group that is actually passed. Other heads are computed.
*/
private final @NonNull List<@NonNull Node> headNodes = new ArrayList<@NonNull Node>();
/**
* The subset of possible guard nodes that all callers can pass..
*/
private final @NonNull List<@NonNull Node> guardNodes = new ArrayList<@NonNull Node>();
/**
* Mapping from the scheduled Nodes to their QVTi variables.
*/
private final @NonNull Map<@NonNull Node, @NonNull Variable> node2variable = new HashMap<@NonNull Node, @NonNull Variable>();
/**
* Mapping from the TypedModel to its ImperativeDomain.
*/
private final @NonNull Map<@NonNull TypedModel, @NonNull ImperativeDomain> typedModel2domain = new HashMap<@NonNull TypedModel, @NonNull ImperativeDomain>();
/**
* Mapping from QVTi expression to Schedule Node.
*/
// private final @NonNull Map<TypedElement, Node> qvti2node = new HashMap<TypedElement, Node>();
private final @NonNull ExpressionCreator expressionCreator;
private final @NonNull ExpressionCreator inlineExpressionCreator = new InlineExpressionCreator();
public BasicRegion2Mapping(@NonNull QVTs2QVTiVisitor visitor, @NonNull Region region) {
super(visitor, region);
this.expressionCreator = new ExpressionCreator();
@SuppressWarnings("unused")String name = region.getName();
createEmptyDomainsAndPatterns();
createHeadAndGuardNodeVariables();
createNavigablePredicates();
createExternalPredicates();
createRealizedVariables();
createPropertyAssignments();
createConnectionAssignments();
createPollingDependencies();
}
/**
* Add asPredicate to the bottom pattern if any bottom variable is referenced, otherwise add to the guard pattern.
*/
protected void addPredicate(@NonNull Predicate asPredicate) {
boolean isBottom = false;
for (TreeIterator<EObject> tit = asPredicate.eAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof VariableExp) {
VariableDeclaration variable = ((VariableExp)eObject).getReferredVariable();
if ((variable != null) && (variable.eContainer() instanceof BottomPattern)) {
isBottom = true;
break;
}
}
}
if (isBottom) {
mapping.getBottomPattern().getPredicate().add(asPredicate);
}
else {
mapping.getGuardPattern().getPredicate().add(asPredicate);
}
}
/* @Override
public void checkAndEnforceRealizations(@NonNull Map<TypedModel, Map<Property, List<NavigationEdge>>> typedModel2property2realizedEdges) {
boolean doDebug = QVTs2QVTiVisitor.POLLED_PROPERTIES.isActive();
for (NavigationEdge predicatedEdge : region.getPredicatedNavigationEdges()) {
Node laterNode = predicatedEdge.getTarget();
ClassDatumAnalysis classDatumAnalysis = laterNode.getClassDatumAnalysis();
TypedModel typedModel = classDatumAnalysis.getTypedModel();
Property property = predicatedEdge.getProperty();
Map<Property, List<NavigationEdge>> property2realizedEdges = typedModel2property2realizedEdges.get(typedModel);
assert property2realizedEdges != null;
List<NavigationEdge> realizedEdges = property2realizedEdges.get(property);
assert realizedEdges != null;
for (NavigationEdge realizedEdge : realizedEdges) {
Node earlierNode = realizedEdge.getTarget();
Region earlierRegion = earlierNode.getRegion();
boolean isAfter = isAfter(earlierRegion, region);
if (!isAfter) {
Area laterArea = QVTimperativeUtil.getArea(mapping, typedModel);
if (laterArea instanceof ImperativeArea) {
if (((ImperativeArea)laterArea).getCheckedProperties().add(property)) {
if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" checks " + property +
" at " + region.getEarliestIndex() + ".." + region.getLatestIndex() + " in " + typedModel + " for " + region);
}
}
}
AbstractRegion2Mapping earlierRegion2Mapping = visitor.getRegion2Mapping(earlierRegion);
Mapping earlierMapping = earlierRegion2Mapping.getMapping();
Area earlierArea = QVTimperativeUtil.getArea(earlierMapping, typedModel);
if (earlierArea instanceof ImperativeArea) {
if (((ImperativeArea)earlierArea).getEnforcedProperties().add(property)) {
if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" enforces " + property +
" at " + earlierRegion.getEarliestIndex() + ".." + earlierRegion.getLatestIndex() + " in " + typedModel + " for " + earlierRegion);
}
}
}
}
else if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" " + region + "::" + laterNode.getName() + "(" + region.getEarliestIndex() + ".." + region.getLatestIndex() + ")" +
" isAfter (" + earlierRegion.getEarliestIndex() + ".." + earlierRegion.getLatestIndex() + ")" + earlierRegion + "::" + earlierNode.getName());
}
}
}
} */
/* @Override
public void computeCheckedProperties() {
boolean doDebug = QVTs2QVTiVisitor.POLLED_PROPERTIES.isActive();
if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println("Computing polled properties for " + this);
}
for (NavigationEdge laterEdge : region.getNavigationEdges()) {
Node laterNode = laterEdge.getTarget();
// Region laterRegion = laterNode.getRegion();
for (@SuppressWarnings("null")@NonNull Node earlierNode : laterNode.getUsedBindingSources()) {
Region earlierRegion = earlierNode.getRegion();
boolean isAfter = isAfter(earlierRegion, region);
if (!isAfter) {
ClassDatumAnalysis classDatumAnalysis = laterNode.getClassDatumAnalysis();
TypedModel typedModel = classDatumAnalysis.getTypedModel();
Property property = laterEdge.getProperty();
Area laterArea = QVTimperativeUtil.getArea(mapping, typedModel);
if (laterArea instanceof ImperativeArea) {
if (((ImperativeArea)laterArea).getCheckedProperties().add(property)) {
if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" checks " + property +
" at " + region.getEarliestIndex() + ".." + region.getLatestIndex() + " in " + typedModel + " for " + region);
}
}
}
AbstractRegion2Mapping earlierRegion2Mapping = visitor.getRegion2Mapping(earlierRegion);
Mapping earlierMapping = earlierRegion2Mapping.getMapping();
Area earlierArea = QVTimperativeUtil.getArea(earlierMapping, typedModel);
if (earlierArea instanceof ImperativeArea) {
if (((ImperativeArea)earlierArea).getEnforcedProperties().add(property)) {
if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" enforces " + property +
" at " + earlierRegion.getEarliestIndex() + ".." + earlierRegion.getLatestIndex() + " in " + typedModel + " for " + earlierRegion);
}
}
}
}
else if (doDebug) {
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(" " + region + "::" + laterNode.getName() + "(" + region.getEarliestIndex() + ".." + region.getLatestIndex() + ")" +
" isAfter (" + earlierRegion.getEarliestIndex() + ".." + earlierRegion.getLatestIndex() + ")" + earlierRegion + "::" + earlierNode.getName());
}
}
}
} */
private @NonNull Variable createBottomVariable(@NonNull Node node, @Nullable OCLExpression initExpression) {
Area area = getArea(node.getClassDatumAnalysis());
Type variableType = node.getCompleteClass().getPrimaryClass();
assert variableType != null;
boolean isRequired = true;
for (@NonNull TypedElement typedElement : node.getTypedElements()) {
if (!typedElement.isIsRequired()) {
isRequired = false;
}
}
if ((initExpression != null) && initExpression.isIsRequired()) {
isRequired = true;
}
Variable variable = PivotUtil.createVariable(getSafeName(node), variableType, isRequired, null);
BottomPattern bottomPattern = area.getBottomPattern();
bottomPattern.getVariable().add(variable);
if (initExpression != null) {
VariableAssignment variableAssignment = helper.createVariableAssignment(variable, initExpression);
mapping.getBottomPattern().getAssignment().add(variableAssignment);
}
Variable oldVariable = node2variable.put(node, variable);
assert oldVariable == null;
return variable;
}
private void createClassPropertyAssignments(@NonNull Iterable<@NonNull List<@NonNull NavigationEdge>> classAssignments) {
for (@NonNull List<@NonNull NavigationEdge> edges : classAssignments) {
for (@NonNull NavigationEdge edge : edges) {
Node sourceNode = edge.getSource();
Node targetNode = edge.getTarget();
OCLExpression slotVariableExp = createVariableExp(sourceNode);
Property property = edge.getProperty();
OCLExpression targetVariableExp = createVariableExp(targetNode);
PropertyAssignment propertyAssignment = QVTimperativeUtil.createPropertyAssignment(slotVariableExp, property, targetVariableExp);
mapping.getBottomPattern().getAssignment().add(propertyAssignment);
}
}
}
/**
* Create accumulation assignments for connections.
*/
private void createConnectionAssignments() {
if (connection2variable != null) {
for (@NonNull NodeConnection connection : connection2variable.keySet()) {
Node sourceNode = connection.getSource(region);
OCLExpression variableExpression = createVariableExp(sourceNode);
ConnectionVariable connectionVariable = (ConnectionVariable)connection2variable.get(connection);
assert connectionVariable != null;
createConnectionAssignment(connectionVariable, variableExpression);
}
}
}
/**
* Create the domains and guard/bottom patterns.
*/
private void createEmptyDomainsAndPatterns() {
Set<@NonNull TypedModel> checkableTypedModels = new HashSet<@NonNull TypedModel>();
Set<@NonNull TypedModel> enforceableTypedModels = new HashSet<@NonNull TypedModel>();
for (@NonNull Node node : region.getNodes()) {
ClassDatumAnalysis classDatumAnalysis = node.getClassDatumAnalysis();
Type type = classDatumAnalysis.getClassDatum().getType();
if (!(type instanceof DataType) && !(type instanceof AnyType) && !(type instanceof VoidType) && !(type instanceof InvalidType)) {
DomainUsage domainUsage = classDatumAnalysis.getDomainUsage();
if (domainUsage.isInput()) { // EObject is $primitive$
for (@NonNull TypedModel typedModel : domainUsage.getTypedModels()) {
TypedModel qvtiTypedModel = visitor.getQVTiTypedModel(typedModel);
assert qvtiTypedModel != null;
checkableTypedModels.add(qvtiTypedModel);
}
}
if (domainUsage.isOutput()) { // EObject is $primitive$
for (@NonNull TypedModel typedModel : domainUsage.getTypedModels()) {
TypedModel qvtiTypedModel = visitor.getQVTiTypedModel(typedModel);
assert qvtiTypedModel != null;
enforceableTypedModels.add(qvtiTypedModel);
}
}
}
}
checkableTypedModels.removeAll(enforceableTypedModels);
for (@NonNull TypedModel qvtiTypedModel : checkableTypedModels) {
ImperativeDomain domain = QVTimperativeUtil.createImperativeDomain(qvtiTypedModel);
domain.setIsCheckable(true);
mapping.getDomain().add(domain);
ImperativeDomain oldDomain = typedModel2domain.put(qvtiTypedModel, domain);
assert oldDomain == null;
}
for (@NonNull TypedModel qvtiTypedModel : enforceableTypedModels) {
ImperativeDomain domain = QVTimperativeUtil.createImperativeDomain(qvtiTypedModel);
domain.setIsEnforceable(true);
mapping.getDomain().add(domain);
ImperativeDomain oldDomain = typedModel2domain.put(qvtiTypedModel, domain);
assert oldDomain == null;
}
ECollections.sort(ClassUtil.nullFree(mapping.getDomain()), DomainNameComparator.INSTANCE);
}
/**
* Create a predicate expression for each TRUE 'head'.
*/
private void createExternalPredicates() {
for (@NonNull Node node : region.getNodes()) {
if (node.isTrue()) {
for (@NonNull Edge edge : node.getArgumentEdges()) {
Node predicateNode = edge.getSource();
for (@NonNull TypedElement typedElement : predicateNode.getTypedElements()) {
OCLExpression conditionExpression = typedElement.accept(inlineExpressionCreator);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(conditionExpression);
addPredicate(asPredicate);
}
}
}
}
}
private @NonNull Variable createGuardVariable(@NonNull Node guardNode) {
Area area = getArea(guardNode.getClassDatumAnalysis());
GuardPattern guardPattern = area.getGuardPattern();
assert guardPattern != null;
Type variableType = guardNode.getCompleteClass().getPrimaryClass();
Variable guardVariable = PivotUtil.createVariable(getSafeName(guardNode), variableType, true, null);
guardPattern.getVariable().add(guardVariable);
Variable oldVariable = node2variable.put(guardNode, guardVariable);
assert oldVariable == null;
return guardVariable;
}
/**
* Identify the headNodes/guardNodes and create a guard variable for each guard node.
*/
private void createHeadAndGuardNodeVariables() {
Set<@NonNull Region> headCallingRegions = new HashSet<@NonNull Region>();
Iterable<@NonNull Edge> recursionEdges = region.getRecursionEdges();
if (Iterables.size(recursionEdges) > 0) {
headCallingRegions.add(region);
}
for (@NonNull Node headNode : region.getHeadNodes()) {
Node bestHeadNode = null;
boolean isExtraGuard = false;
Iterable<@NonNull Node> callingSources = headNode.getPassedBindingSources();
if (!Iterables.isEmpty(callingSources)) {
bestHeadNode = headNode;
}
else if (headNode.getNodeRole().isExtraGuardVariable()) {
isExtraGuard = true;
}
for (@NonNull Node callingSource : callingSources) {
headCallingRegions.add(callingSource.getRegion());
}
if (bestHeadNode != null) {
headNodes.add(bestHeadNode);
}
else if (!isExtraGuard) {
System.err.println("No best head for " + region);
}
}
guardNodes.addAll(headNodes);
for (@NonNull Node guardNode : region.getGuardNodes()) {
if (!guardNodes.contains(guardNode)) {
NodeConnection connection = guardNode.getIncomingUsedConnection();
if (connection != null) { // null for LOADED
Set<Region> guardCallingRegions = new HashSet<Region>();
boolean canBeGuard = true;
for (@NonNull Node callingSource : guardNode.getUsedBindingSources()) {
if (callingSource.getNodeRole().isComposed()) {
canBeGuard = false;
break;
}
guardCallingRegions.add(callingSource.getRegion());
}
for (@NonNull Node recursionSource : guardNode.getRecursionSources()) {
guardCallingRegions.add(recursionSource.getRegion());
}
if (canBeGuard && guardCallingRegions.containsAll(headCallingRegions) && guardCallingRegions.contains(connection.getCommonRegion())) {
if (!guardNodes.contains(guardNode)) {
guardNodes.add(guardNode);
}
}
}
}
}
Collections.sort(guardNodes, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull Node guardNode : guardNodes) {
createGuardVariable(guardNode);
}
//
// Create any connectionVariable guards
//
createConnectionGuardVariables();
}
private void createMappingStatements(@NonNull Map<@NonNull Region, @NonNull Map<@NonNull Node, @NonNull Node>> calls) {
MappingStatement mappingStatement = null;
Map<@NonNull Variable, @NonNull OCLExpression> loopVariables = null;
for (Map.Entry<@NonNull Region, @NonNull Map<@NonNull Node, @NonNull Node>> entry : calls.entrySet()) {
@NonNull Region calledRegion = entry.getKey();
AbstractRegion2Mapping calledRegion2Mapping = visitor.getRegion2Mapping(calledRegion);
List<@NonNull MappingCallBinding> mappingCallBindings = new ArrayList<@NonNull MappingCallBinding>();
for (Map.Entry<@NonNull Node, @NonNull Node> entry2 : entry.getValue().entrySet()) {
@NonNull Node sourceNode = entry2.getKey();
@NonNull Node targetNode = entry2.getValue();
OCLExpression sourceExpression = getSourceExpression(sourceNode);
Type type = sourceExpression.getType();
if (type instanceof CollectionType) {
if (loopVariables == null) {
loopVariables = new HashMap<@NonNull Variable, @NonNull OCLExpression>();
}
Type elementType = ((CollectionType)type).getElementType();
assert elementType != null;
Variable loopVariable = PivotUtil.createVariable("loop" + loopVariables.size(), elementType, true, sourceExpression);
loopVariables.put(loopVariable, sourceExpression);
sourceExpression = PivotUtil.createVariableExp(loopVariable);
}
Variable guardVariable = calledRegion2Mapping.getGuardVariable(targetNode);
mappingCallBindings.add(QVTimperativeUtil.createMappingCallBinding(guardVariable, sourceExpression));
// mappingCallBindings.add(QVTimperativeUtil.createMappingLoop(source, iterator, mappingStatement);
}
/* Mapping calledMapping = calledRegion2Mapping.getMapping();
for (Node node : calledRegion2Mapping.getRegion().getPredicatedNodes()) {
for (Edge edge : node.getIncomingUsedBindingEdges()) {
Node sourceNode = edge.getSource();
if (sourceNode.getRegion() == region) {
OCLExpression sourceExpression = createVariableExp(sourceNode);
Variable guardVariable = calledRegion2Mapping.getGuardVariable(edge.getTarget());
MappingCallBinding mappingCallBinding = QVTimperativeUtil.createMappingCallBinding(guardVariable, sourceExpression);
if (calledMapping.getPolledClasses().size() > 0) {
mappingCallBinding.setIsPolled(true); // FIXME temporary backward compatibility
}
mappingCallBindings.add(mappingCallBinding);
}
else {
// FIXME find source
}
}
} */
Collections.sort(mappingCallBindings, QVTimperativeUtil.MappingCallBindingComparator.INSTANCE);
MappingStatement mappingCallStatement = calledRegion2Mapping.createMappingCall(mappingCallBindings);
if (loopVariables != null) {
for (Map.Entry<@NonNull Variable, @NonNull OCLExpression> loopEntry : loopVariables.entrySet()) {
@NonNull Variable loopVariable = loopEntry.getKey();
@NonNull OCLExpression loopSource = loopEntry.getValue();
mappingCallStatement = QVTimperativeUtil.createMappingLoop(loopSource, loopVariable, mappingCallStatement);
}
}
mappingStatement = QVTimperativeUtil.addMappingStatement(mappingStatement, mappingCallStatement);
}
mapping.setMappingStatement(mappingStatement);
}
/**
* Recurse over the guard nodes and loaded/predicates region and convert the edges to predicates and non-guard nodes to unrealized variables.
*/
private void createNavigablePredicates() {
@SuppressWarnings("unused")String name = region.getName();
//
// Categorize the relevant navigation edges
//
Set<@NonNull NavigationEdge> backwardEdges = new HashSet<@NonNull NavigationEdge>();
Set<@NonNull NavigationEdge> forwardEdges = new HashSet<@NonNull NavigationEdge>();
// Set<@NonNull NavigationEdge> attributeEdges = new HashSet<@NonNull NavigationEdge>();
/*
* The nodes that form the traversal forest.
*/
Set<@NonNull Node> navigableNodes = new HashSet<@NonNull Node>();
/*
* The edges that are not traversed while locating each node.
*/
Set<@NonNull NavigationEdge> untraversedEdges = new HashSet<@NonNull NavigationEdge>();
for (@NonNull NavigationEdge edge : region.getNavigationEdges()) {
if (edge.isRealized()) {}
else if (!edge.isNavigable()) {}
else if (edge.isCast()) {}
else {
assert !edge.isArgument();
assert !edge.isComputation();
Node sourceNode = edge.getSource();
navigableNodes.add(sourceNode);
Node targetNode = edge.getTarget();
if (targetNode.isNull()) {
untraversedEdges.add(edge);
}
else {
targetNode = RegionUtil.getCastTarget(targetNode);
Property property = edge.getProperty();
if (property.isIsImplicit()) {
backwardEdges.add(edge);
navigableNodes.add(targetNode);
}
// else if (targetNode.isAttributeNode()) {
// attributeEdges.add(edge);
// }
else {
forwardEdges.add(edge);
navigableNodes.add(targetNode);
}
}
}
}
//
// Identify the edges that need traversal to reach as all nodes preferring forwardEdges.
//
/*
* The edges that are traversed while locating each node and their depth in the traversal forest.
*/
Map<@NonNull NavigationEdge, @NonNull Integer> traversedEdge2depth = new HashMap<@NonNull NavigationEdge, @NonNull Integer>();
/*
* The incoming edge for each node in the traversal forest, null at a root.
*/
Map<@NonNull Node, @Nullable NavigationEdge> traversedNode2incomingEdge = new HashMap<@NonNull Node, @Nullable NavigationEdge>();
for (@NonNull Node guardNode : guardNodes) {
traversedNode2incomingEdge.put(guardNode, null);
}
Set<@NonNull Node> moreNodes = new HashSet<@NonNull Node>(guardNodes);
int depth = 0;
while (moreNodes.size() > 0) {
//
// Select the forward edges that make progress.
//
Set<@NonNull Node> moreMoreNodes = new HashSet<@NonNull Node>();
for (@NonNull Node sourceNode : moreNodes) {
for (@NonNull NavigationEdge edge : sourceNode.getNavigationEdges()) {
if (forwardEdges.contains(edge)) {
Node targetNode = RegionUtil.getCastTarget(edge.getTarget());
if (!traversedNode2incomingEdge.containsKey(targetNode)) {
traversedNode2incomingEdge.put(targetNode, edge);
moreMoreNodes.add(targetNode);
traversedEdge2depth.put(edge, depth);
}
else {
untraversedEdges.add(edge);
}
}
}
}
if (moreMoreNodes.isEmpty() && (traversedNode2incomingEdge.size() < navigableNodes.size())) {
//
// Unblock an incomplete traversal by choosing a backward edge.
//
for (@NonNull NavigationEdge edge : backwardEdges) { // FIXME maintain reducing list of possibles
Node sourceNode = edge.getSource();
if (traversedNode2incomingEdge.containsKey(sourceNode)) {
Node targetNode = edge.getTarget();
if (!traversedNode2incomingEdge.containsKey(targetNode)) {
traversedNode2incomingEdge.put(targetNode, edge);
moreMoreNodes.add(targetNode);
traversedEdge2depth.put(edge, depth);
break;
}
}
}
}
moreNodes = moreMoreNodes;
depth++;
}
//
// Traverse the attributes too.
//
/* for (@NonNull NavigationEdge edge : attributeEdges) {
Node targetNode = edge.getTarget();
if (!traversedNode2incomingEdge.containsKey(targetNode)) {
traversedNode2incomingEdge.put(targetNode, edge);
}
else {
untraversedEdges.add(edge);
}
} */
//
// Identify the remaining untraversed edges that are not used to reach nodes and so must be reified as predicates to check nodes.
//
for (@NonNull NavigationEdge edge : forwardEdges) {
if (!traversedEdge2depth.containsKey(edge)) {
NavigationEdge oppositeEdge = getOppositeEdge(edge);
if ((oppositeEdge == null) || !traversedEdge2depth.containsKey(oppositeEdge)) {
untraversedEdges.add(edge);
}
}
}
for (@NonNull NavigationEdge edge : backwardEdges) {
if (!traversedEdge2depth.containsKey(edge) && !untraversedEdges.contains(edge)) {
NavigationEdge oppositeEdge = getOppositeEdge(edge);
if ((oppositeEdge == null) || (!traversedEdge2depth.containsKey(oppositeEdge) && !untraversedEdges.contains(edge))) {
untraversedEdges.add(edge);
}
}
}
//
// Order the traversal edges shallowest first then alphabetically.
//
List<@NonNull NavigationEdge> traversedEdges = new ArrayList<@NonNull NavigationEdge>(traversedEdge2depth.keySet());
Collections.sort(traversedEdges, new Comparator<@NonNull NavigationEdge>() {
@Override
public int compare(@NonNull NavigationEdge o1, @NonNull NavigationEdge o2) {
Integer d1 = traversedEdge2depth.get(o1);
Integer d2 = traversedEdge2depth.get(o2);
assert (d1 != null) && (d2 != null);
if (d1 != d2) {
return d1 - d2;
}
String n1 = o1.getDisplayName();
String n2 = o2.getDisplayName();
return n1.compareTo(n2);
}
});
//
// Convert the traversed edges to unrealized variables and initializers.
//
for (@NonNull NavigationEdge traversedEdge : traversedEdges) {
Node sourceNode = traversedEdge.getSource();
Node targetNode = traversedEdge.getTarget();
Property property = traversedEdge.getProperty();
OCLExpression sourceExp = createVariableExp(sourceNode);
OCLExpression source2targetExp = createCallExp(sourceExp, property);
if (targetNode.isAttributeNode()) {
Variable attributeVariable = node2variable.get(targetNode);
assert attributeVariable == null;
createBottomVariable(targetNode, source2targetExp);
}
else {
Variable classVariable = node2variable.get(targetNode);
assert classVariable == null;
createBottomVariable(targetNode, source2targetExp);
/* }
else {
OCLExpression ownedInit = classVariable.getOwnedInit();
assert ownedInit == null;
if (source2targetExp != null) {
Type variableType = classVariable.getType();
Type initType = source2targetExp.getType();
assert variableType != null;
if (!initType.conformsTo(visitor.getStandardLibrary(), variableType)) {
source2targetExp = createOclAsTypeCallExp(source2targetExp, variableType);
}
}
classVariable.setOwnedInit(source2targetExp);
} */
}
}
//
// Convert the untraversed edges to predicates.
//
for (@NonNull NavigationEdge untraversedEdge : untraversedEdges) {
Node sourceNode = untraversedEdge.getSource();
Node targetNode = untraversedEdge.getTarget();
Property property = untraversedEdge.getProperty();
OCLExpression sourceExp = createVariableExp(sourceNode);
OCLExpression targetExp = createVariableExp(targetNode);
OCLExpression source2targetExp = createCallExp(sourceExp, property);
OCLExpression matchesExp = targetNode.isNull()
? helper.createOperationCallExp(source2targetExp, "=", targetExp)
: helper.createOperationCallExp(targetExp, "=", source2targetExp);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(matchesExp);
addPredicate(asPredicate);
}
/* Set<@NonNull Node> reachableNodes = new HashSet<@NonNull Node>(guardNodes);
List<@NonNull Node> sourcesList = new ArrayList<@NonNull Node>(guardNodes);
for (int i = 0; i < sourcesList.size(); i++) {
@NonNull Node sourceNode = sourcesList.get(i);
for (@NonNull NavigationEdge edge : sourceNode.getNavigationEdges()) { // if !edge.getEdgeRole().isRealized() && !targetNode.isNull()
EdgeRole edgeRole = edge.getEdgeRole();
if (!edgeRole.isRealized()) {
Node targetNode = edge.getTarget();
if (targetNode.isNull()) {
// FIXME check in caller
}
else if (targetNode.isIterator()) {
// Process in LoopExp
}
else {
Property property = edge.getProperty();
if (reachableNodes.add(targetNode)) {
if (targetNode.isAttributeNode()) {
if (targetNode.getCompleteClass().getPrimaryClass() instanceof CollectionType) {
sourcesList.add(targetNode);
}
OCLExpression sourceExp = createVariableExp(sourceNode);
OCLExpression source2targetExp = createCallExp(sourceExp, property);
// qvti2node.put(source2targetExp, targetNode);
Variable attributeVariable = node2variable.get(targetNode);
if (attributeVariable == null) {
createUnrealizedVariable(bottomPattern, targetNode, source2targetExp);
}
/* else {
OCLExpression targetExp = PivotUtil.createVariableExp(attributeVariable);
OCLExpression matchesExp = createOperationCallExp(targetExp, visitor.getEqualsOperation(), source2targetExp);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(matchesExp);
mapping.getBottomPattern().getPredicate().add(asPredicate);
} * /
}
else if (expressionCreator.isConditional(targetNode)) {
}
else if (!guardNodes.contains(targetNode)) {
sourcesList.add(targetNode);
OCLExpression sourceExp = createVariableExp(sourceNode);
OCLExpression source2targetExp = createCallExp(sourceExp, property);
Variable classVariable = node2variable.get(targetNode);
if (classVariable == null) {
classVariable = createUnrealizedVariable(bottomPattern, targetNode, source2targetExp);
}
else {
OCLExpression ownedInit = classVariable.getOwnedInit();
assert ownedInit == null;
if (source2targetExp != null) {
Type variableType = classVariable.getType();
Type initType = source2targetExp.getType();
assert variableType != null;
if (!initType.conformsTo(visitor.getStandardLibrary(), variableType)) {
source2targetExp = createOclAsTypeCallExp(source2targetExp, variableType);
}
}
classVariable.setOwnedInit(source2targetExp);
}
/* else {
OCLExpression targetExp = PivotUtil.createVariableExp(attributeVariable);
OCLExpression matchesExp = createOperationCallExp(targetExp, visitor.getEqualsOperation(), source2targetExp);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(matchesExp);
mapping.getBottomPattern().getPredicate().add(asPredicate);
} * /
}
else {
sourcesList.add(targetNode);
Iterable<@NonNull Node> callingSources = targetNode.getPassedBindingSources(); // Used
if (Iterables.size(callingSources) <= 0) { // FIXME check predicate in source etc
OCLExpression sourceExp = createVariableExp(sourceNode);
OCLExpression targetExp = createVariableExp(targetNode);
OCLExpression source2targetExp = createCallExp(sourceExp, property);
OCLExpression matchesExp = createOperationCallExp(targetExp, visitor.getEqualsOperation(), source2targetExp);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(matchesExp);
addPredicate(asPredicate);
}
}
}
}
}
}
} */
}
private void createPollingDependencies() {
DomainUsage anyUsage = region.getSchedulerConstants().getDomainAnalysis().getAnyUsage();
for (@NonNull TypedModel qvtpTypedModel : anyUsage.getTypedModels()) {
TypedModel qvtiTypedModel = visitor.getQVTiTypedModel(qvtpTypedModel);
ImperativeDomain domain = typedModel2domain.get(qvtiTypedModel);
ImperativeArea imperativeArea = domain != null ? (ImperativeArea)domain : mapping;
Iterable<@NonNull NavigationEdge> checkedEdges = region.getCheckedEdges(qvtpTypedModel);
if (checkedEdges != null) {
List<Property> checkedProperties = imperativeArea.getCheckedProperties();
for (NavigationEdge checkedEdge : checkedEdges) {
checkedProperties.add(checkedEdge.getProperty());
}
}
Iterable<@NonNull NavigationEdge> enforcedEdges = region.getEnforcedEdges(qvtpTypedModel);
if (enforcedEdges != null) {
List<@NonNull Property> enforcedProperties = ClassUtil.nullFree(imperativeArea.getEnforcedProperties());
for (@NonNull NavigationEdge enforcedEdge : enforcedEdges) {
enforcedProperties.add(enforcedEdge.getProperty());
}
}
}
}
private void createPropertyAssignments() {
Map<@NonNull Node, @NonNull List<@NonNull NavigationEdge>> classAssignments = null;
ImperativeBottomPattern bottomPattern = (ImperativeBottomPattern) mapping.getBottomPattern();
for (@NonNull NavigationEdge edge : region.getRealizedNavigationEdges()) {
Node sourceNode = edge.getSource();
Node targetNode = edge.getTarget();
if (targetNode.isAttributeNode()) {
OCLExpression slotVariableExp = createVariableExp(sourceNode);
Property property = edge.getProperty();
OCLExpression valueExp = expressionCreator.getExpression(targetNode);
if (valueExp == null) {
valueExp = expressionCreator.getExpression(targetNode); // FIXME debugging
}
if (valueExp != null) {
PropertyAssignment propertyAssignment = QVTimperativeUtil.createPropertyAssignment(slotVariableExp, property, valueExp);
bottomPattern.getAssignment().add(propertyAssignment);
}
else {
System.err.println("No assignment in " + this + " to " + slotVariableExp);
}
}
else {
if (classAssignments == null) {
classAssignments = new HashMap<@NonNull Node, @NonNull List<@NonNull NavigationEdge>>();
}
List<@NonNull NavigationEdge> edges = classAssignments.get(sourceNode);
if (edges == null) {
edges = new ArrayList<@NonNull NavigationEdge>();
classAssignments.put(sourceNode, edges);
}
edges.add(edge);
}
}
if (classAssignments != null) {
pruneClassAssignments(classAssignments);
Collection<@NonNull List<@NonNull NavigationEdge>> values = classAssignments.values();
createClassPropertyAssignments(values);
}
@SuppressWarnings("null")
@NonNull EList<@NonNull Assignment> bottomAssignments = bottomPattern.getOrderedAssignment();
ECollections.sort(bottomAssignments, new AssignmentComparator(bottomAssignments));
}
private void createRealizedVariables() {
for (@NonNull Node node : region.getRealizedVariableNodes()) {
OCLExpression constructor = null;
for (Edge edge : node.getIncomingEdges()) {
if (edge.isResult()) {
Node sourceNode = edge.getSource();
if (sourceNode.isOperation()) {
constructor = ((OperationCallExp)sourceNode.getTypedElements().iterator().next()).accept(expressionCreator);
}
}
}
ClassDatumAnalysis classDatumAnalysis = node.getClassDatumAnalysis();
BottomPattern bottomPattern = getArea(classDatumAnalysis).getBottomPattern();
RealizedVariable realizedVariable = QVTimperativeUtil.createRealizedVariable(getSafeName(node), classDatumAnalysis.getCompleteClass().getPrimaryClass());
realizedVariable.setOwnedInit(constructor);
bottomPattern.getRealizedVariable().add(realizedVariable);
Variable oldVariable = node2variable.put(node, realizedVariable);
assert oldVariable == null;
}
}
@Override
public void createStatements() {
Map<@NonNull Region, @NonNull Map<@NonNull Node, @NonNull Node>> calls = null;
// for (@SuppressWarnings("null")@NonNull Region calledRegion : getEarliestFirstCalledRegions()) {
for (@NonNull Region calledRegion : region.getCallableChildren()) {
if (calls == null) {
calls = new HashMap<@NonNull Region, @NonNull Map<@NonNull Node, @NonNull Node>>();
}
Map<@NonNull Node, @NonNull Node> source2target = calls.get(calledRegion);
if (source2target == null) {
source2target = new HashMap<@NonNull Node, @NonNull Node>();
calls.put(calledRegion, source2target);
}
AbstractRegion2Mapping calledRegion2Mapping = visitor.getRegion2Mapping(calledRegion);
for (@NonNull Node calledGuardNode : calledRegion2Mapping.getGuardNodes()) {
for (@NonNull Node callingNode : calledGuardNode.getPassedBindingSources()) {
if (callingNode.getRegion() == region) {
Node oldNode = source2target.put(callingNode, calledGuardNode);
assert oldNode == null;
}
}
for (@NonNull Node callingNode : calledGuardNode.getUsedBindingSources()) {
if (callingNode.getRegion() == region) {
Node oldNode = source2target.put(callingNode, calledGuardNode);
assert oldNode == null;
}
}
}
}
if (calls != null) {
createMappingStatements(calls);
}
}
private @NonNull OCLExpression createVariableExp(@NonNull Node node) {
if (node.isNull()) {
return helper.createNullLiteralExp();
}
else {
Variable variable = node2variable.get(node);
if (variable == null) {
for (@NonNull Edge edge : node.getIncomingEdges()) {
if (edge.isArgument() || edge.isCast()) {
OCLExpression initExpression = edge.getSource().getTypedElements().iterator().next().accept(expressionCreator);
variable = createBottomVariable(node, initExpression);
break;
}
}
}
if (variable == null) {
for (@NonNull Edge edge : node.getIncomingEdges()) {
boolean isPredicated = edge.isPredicated();
boolean isNavigable = edge.isNavigable();
boolean isNavigation = edge.isNavigation();
if (isPredicated && !isNavigable && isNavigation) {
OCLExpression initExpression = edge.getSource().getTypedElements().iterator().next().accept(expressionCreator);
variable = createBottomVariable(node, initExpression);
break;
}
}
}
if (variable == null) {
System.err.println("Creating dummy variable for " + node + " in " + region);
BottomPattern bottomPattern = mapping.getBottomPattern();
assert bottomPattern != null;
Type variableType = node.getCompleteClass().getPrimaryClass();
assert variableType != null;
variable = PivotUtil.createVariable(getSafeName(node), variableType, false, null);
bottomPattern.getVariable().add(variable);
Variable oldVariable = node2variable.put(node, variable);
assert oldVariable == null;
}
return PivotUtil.createVariableExp(variable);
}
}
/* private @Nullable Integer depthRecursion(@NonNull Node node, @NonNull Map<Node, Integer> node2pathDepth,
@NonNull Map<Node, Integer> node2acyclicDepth, @NonNull Map<Node, Integer> node2cyclicDepth) {
Integer pathDepth = node2pathDepth.get(node);
if (pathDepth != null) {
return pathDepth;
}
Integer recursiveDepth = null;
pathDepth = node2pathDepth.size();
node2pathDepth.put(node, pathDepth);
for (Edge edge : node.getOutgoingEdges()) {
if (edge.isNavigation() || edge.isComputation()) {
Node nextNode = edge.getTarget();
Integer nextDepth = depthRecursion(nextNode, node2pathDepth, node2acyclicDepth, node2cyclicDepth);
if (nextDepth == null) {
Integer acyclicDepth = node2acyclicDepth.get(node);
if ((acyclicDepth == null) || (acyclicDepth < pathDepth)) {
node2acyclicDepth.put(node, pathDepth);
}
}
else {
Integer cyclicDepth = node2cyclicDepth.get(node);
if ((cyclicDepth == null) || (pathDepth < cyclicDepth)) {
node2cyclicDepth.put(node, pathDepth);
}
if ((recursiveDepth == null) || (nextDepth < recursiveDepth)) {
recursiveDepth = nextDepth;
}
}
}
}
node2pathDepth.remove(node);
return recursiveDepth;
} */
private @NonNull Area getArea(@NonNull ClassDatumAnalysis classDatumAnalysis) {
TypedModel qvtpTypedModel = classDatumAnalysis.getTypedModel();
ImperativeDomain coreDomain = typedModel2domain.get(qvtpTypedModel);
if (coreDomain != null) {
return coreDomain;
}
TypedModel qvtiTypedModel = visitor.qvtpTypedModel2qvtiTypedModel.get(qvtpTypedModel); // FIXME shouldn't happen
coreDomain = typedModel2domain.get(qvtiTypedModel);
if (coreDomain != null) {
return coreDomain;
}
// for (Domain domain : mapping.getDomain()) {
// if (domain.getTypedModel() == qvtiTypedModel) {
// return (ImperativeDomain)domain;
// }
// }
return mapping;
}
@Override
public @NonNull List<@NonNull Node> getGuardNodes() {
return guardNodes;
}
@Override
public @NonNull Variable getGuardVariable(@NonNull Node node) {
// Area area = getArea(mapping, node.getClassDatumAnalysis().getDomainUsage());
// String name = getName(node);
// Variable variable = NameUtil.getNameable(area.getGuardPattern().getVariable(),name);
Variable variable = node2variable.get(node);
assert variable != null;
return variable;
}
/* @Override
public @Nullable Node getNode(@Nullable TypedElement typedElement) {
Node node = qvti2node.get(typedElement);
if (node != null) {
return node;
}
else {
return super.getNode(typedElement);
}
} */
private @Nullable NavigationEdge getOppositeEdge(@NonNull NavigationEdge edge) {
Node targetNode = edge.getTarget();
Property property = edge.getProperty();
Property oppositeProperty = property.getOpposite();
if (oppositeProperty == null) {
return null;
}
NavigationEdge oppositeEdge = targetNode.getNavigationEdge(oppositeProperty);
if (oppositeEdge == null) {
return null;
}
assert oppositeEdge.getTarget() == edge.getSource();
return oppositeEdge;
}
private @NonNull OCLExpression getSourceExpression(@NonNull Node sourceNode) {
return createVariableExp(sourceNode);
}
public @Nullable Variable getVariable(@NonNull Node node) {
return node2variable.get(node);
}
private boolean isIfExp(@NonNull Node node) {
if (node.isExpression()) {
for (TypedElement typedElement : node.getTypedElements()) {
if (typedElement instanceof IfExp) {
return true;
}
}
}
return false;
}
@Override
public boolean isInfinite() {
if (region.getRecursionEdges().iterator().hasNext()) { // FIXME unduly pessimistic
return true;
}
return false;
}
/**
* Filter classAssignments to retain only one of each opposite-property assignment pair.
*/
private void pruneClassAssignments(@NonNull Map<@NonNull Node, @NonNull List<@NonNull NavigationEdge>> classAssignments) {
for (@NonNull Node sourceNode : new ArrayList<@NonNull Node>(classAssignments.keySet())) {
List<@NonNull NavigationEdge> forwardEdges = classAssignments.get(sourceNode);
assert forwardEdges != null;
for (int iForward = forwardEdges.size()-1; iForward >= 0; iForward--) {
NavigationEdge forwardEdge = forwardEdges.get(iForward);
Node targetNode = forwardEdge.getTarget();
List<@NonNull NavigationEdge> reverseEdges = classAssignments.get(targetNode);
if (reverseEdges != null) {
for (int iReverse = reverseEdges.size()-1; iReverse >= 0; iReverse--) {
NavigationEdge reverseEdge = reverseEdges.get(iReverse);
if (sourceNode == reverseEdge.getTarget()) {
Property forwardProperty = forwardEdge.getProperty();
Property reverseProperty = reverseEdge.getProperty();
if (forwardProperty.getOpposite() == reverseProperty) {
if (forwardProperty.isIsImplicit()) {
forwardEdges.remove(forwardEdge);
}
else if (reverseProperty.isIsImplicit()) {
reverseEdges.remove(reverseEdge);
}
else if (sourceNode.isInternal()) {
forwardEdges.remove(forwardEdge);
}
else if (targetNode.isInternal()) {
reverseEdges.remove(reverseEdge);
}
else { // FIXME do we prefer either direction ?
reverseEdges.remove(reverseEdge);
}
}
}
}
}
}
}
}
}