blob: 4939b55c3ef5fcd153c089f911620d293fcc705e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvts2qvti;
import java.util.ArrayList;
import java.util.Collections;
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.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.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.Element;
import org.eclipse.ocl.pivot.EnumLiteralExp;
import org.eclipse.ocl.pivot.IfExp;
import org.eclipse.ocl.pivot.IterateExp;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.IteratorExp;
import org.eclipse.ocl.pivot.LetExp;
import org.eclipse.ocl.pivot.MapLiteralExp;
import org.eclipse.ocl.pivot.MapLiteralPart;
import org.eclipse.ocl.pivot.MapType;
import org.eclipse.ocl.pivot.NavigationCallExp;
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.Parameter;
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.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.ids.OperationId;
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.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RegionHelper;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.RegionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.checks.CheckedCondition;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.checks.CheckedConditionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.FallibilityAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.MappingPartitionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.PartitionedTransformationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.TransformationPartitioner;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.utilities.ReachabilityForest;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtbase.Function;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.util.AbstractExtendingQVTbaseVisitor;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseLibraryHelper;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtimperative.CheckStatement;
import org.eclipse.qvtd.pivot.qvtimperative.ConnectionVariable;
import org.eclipse.qvtd.pivot.qvtimperative.DeclareStatement;
import org.eclipse.qvtd.pivot.qvtimperative.GuardParameter;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTypedModel;
import org.eclipse.qvtd.pivot.qvtimperative.LoopVariable;
import org.eclipse.qvtd.pivot.qvtimperative.MappingParameter;
import org.eclipse.qvtd.pivot.qvtimperative.MappingParameterBinding;
import org.eclipse.qvtd.pivot.qvtimperative.MappingStatement;
import org.eclipse.qvtd.pivot.qvtimperative.NewStatement;
import org.eclipse.qvtd.pivot.qvtimperative.ObservableStatement;
import org.eclipse.qvtd.pivot.qvtimperative.SetStatement;
import org.eclipse.qvtd.pivot.qvtimperative.SimpleParameter;
import org.eclipse.qvtd.pivot.qvtimperative.Statement;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeHelper;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil;
import org.eclipse.qvtd.pivot.qvtschedule.BooleanLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.ConnectionEnd;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.ExpressionEdge;
import org.eclipse.qvtd.pivot.qvtschedule.IfNode;
import org.eclipse.qvtd.pivot.qvtschedule.KeyPartEdge;
import org.eclipse.qvtd.pivot.qvtschedule.KeyedValueNode;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
import org.eclipse.qvtd.pivot.qvtschedule.NavigationEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.NodeConnection;
import org.eclipse.qvtd.pivot.qvtschedule.NullLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.NumericLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.OperationCallNode;
import org.eclipse.qvtd.pivot.qvtschedule.OperationNode;
import org.eclipse.qvtd.pivot.qvtschedule.OperationParameterEdge;
import org.eclipse.qvtd.pivot.qvtschedule.OperationSelfEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Partition;
import org.eclipse.qvtd.pivot.qvtschedule.PredicateEdge;
import org.eclipse.qvtd.pivot.qvtschedule.PropertyDatum;
import org.eclipse.qvtd.pivot.qvtschedule.Region;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.SharedEdge;
import org.eclipse.qvtd.pivot.qvtschedule.StringLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import org.eclipse.qvtd.pivot.qvttemplate.CollectionTemplateExp;
import org.eclipse.qvtd.runtime.utilities.QVTruntimeUtil;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class BasicPartition2Mapping extends AbstractPartition2Mapping
{
/**
* The OldEdgeSchedule analyses the old (constant, loaded, speculation, predicated) nodes and edges
* to build a linear edge traversal schedule in which unconditional checks that may fail appear
* as early as possible.
*/
private class OldEdgeSchedule
{
/**
* The linear execution schedule for edges.
*/
private @NonNull List<@NonNull Edge> edgeSchedule = new ArrayList<>();
/**
* The edges (and their opposites) in edgeSchedule.
*/
private final @NonNull Set<@NonNull Edge> scheduledEdges = new HashSet<>();
/**
* The nodes at the ends of the edges in edgeSchedule.
*/
private final @NonNull Set<@NonNull Node> scheduledNodes;
public OldEdgeSchedule() {
this.scheduledNodes = Sets.newHashSet(QVTscheduleUtil.getHeadNodes(partition)); // ?? leaf constants
}
private void addEdge(@NonNull Edge edge) {
assert partition.getRole(edge) != null;
if (scheduledEdges.add(edge)) {
NavigationEdge oppositeEdge = null;
if (edge instanceof NavigationEdge) {
oppositeEdge = ((NavigationEdge)edge).getOppositeEdge();
if (oppositeEdge != null) {
boolean wasAdded = scheduledEdges.add(oppositeEdge);
assert wasAdded;
}
}
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
Role sourceNodeRole = partition.getRole(sourceNode);
if ((sourceNodeRole != null) && !sourceNode.isDependency()) {
Node targetNode = QVTscheduleUtil.getTargetNode(edge);
Role targetNodeRole = partition.getRole(targetNode);
if ((targetNodeRole != null) && !targetNode.isDependency()) {
Integer sourceCost = reachabilityForest.getCost(sourceNode);
Integer targetCost = reachabilityForest.getCost(targetNode);
assert (sourceCost != null) && (targetCost != null);// && ((targetCost <= 0) || (sourceCost <= targetCost));
addNode(sourceNode);
addNode(targetNode);
edgeSchedule.add(edge);
}
}
}
}
private void addNode(@NonNull Node targetNode) {
assert partition.getRole(targetNode) != null;
if (scheduledNodes.add(targetNode)) {
Subexpression subexpression = node2subexpression.get(targetNode);
if (subexpression != null) {
for (@NonNull Node inputNode : subexpression.unconditionalInputNodes) {
addNode(inputNode);
}
targetNode = subexpression.resultNode;
addNode(targetNode);
}
Integer targetCost = reachabilityForest.getCost(targetNode);
assert targetCost != null;
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(targetNode)) {
Role edgeRole = partition.getRole(edge);
if ((edgeRole != null) && edgeRole.isOld() && edge.isUnconditional()) {
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
Integer sourceCost = reachabilityForest.getCost(sourceNode);
assert sourceCost != null;
if (sourceCost < targetCost) {
addEdge(edge);
}
}
}
}
}
public @NonNull Iterable<@NonNull CheckedCondition> analyze() {
//
// A dispatch input node must be checked to confirm the correct derivation.
//
Node dispatchNode = regionAnalysis.basicGetDispatchNode();
if (dispatchNode != null) {
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(dispatchNode)) {
Role edgeRole = partition.getRole(edge);
if ((edgeRole != null) && edgeRole.isPredicated()) {
addEdge(edge);
}
}
}
//
// A predicated head node success must be checked before anything else.
//
for (@NonNull Node headNode : headNodes) { // FIXME This should be redundant wrt prioritized CheckConditions
Edge localSuccessEdge = regionAnalysis.basicGetLocalSuccessEdge(headNode);
if (localSuccessEdge != null) {
Role localSuccessEdgeRole = partition.getRole(localSuccessEdge);
if ((localSuccessEdgeRole != null) && localSuccessEdgeRole.isPredicated()) {
addEdge(localSuccessEdge);
}
}
Edge globalSuccessEdge = regionAnalysis.basicGetGlobalSuccessEdge(headNode);
if (globalSuccessEdge != null) {
Role globalSuccessEdgeRole = partition.getRole(globalSuccessEdge);
if ((globalSuccessEdgeRole != null) && globalSuccessEdgeRole.isPredicated()) {
addEdge(globalSuccessEdge);
}
}
}
Set<@NonNull CheckedCondition> checkedConditions = checkedConditionAnalysis.computeCheckedConditions();
int checkableSize = checkedConditions.size();
// if (checkableSize > 0) {
List<@NonNull CheckedCondition> sortedCheckedConditions = new ArrayList<>(checkedConditions);
if (checkableSize > 1) {
Collections.sort(sortedCheckedConditions, new CheckedConditionWeightComparator(BasicPartition2Mapping.this));
}
for (@NonNull CheckedCondition checkedCondition : sortedCheckedConditions) {
Iterable<@NonNull Edge> edges = checkedCondition.getEdges();
if (edges != null) {
for (@NonNull Edge edge : edges) {
addEdge(edge);
}
}
Node node = checkedCondition.getNode();
if (node != null) {
addNode(node);
}
}
// }
List<@NonNull Edge> residualEdges = null;
for (@NonNull Edge edge : checkedConditionAnalysis.getOldUnconditionalEdges()) {
if (!edge2subexpression.containsKey(edge)) {
if (residualEdges == null) {
residualEdges = new ArrayList<>();
}
residualEdges.add(edge);
}
}
if (residualEdges != null) {
Collections.sort(residualEdges, reachabilityForest.getEdgeCostComparator());
for (@NonNull Edge edge : residualEdges) {
addEdge(edge);
}
}
// assert edgeSchedule.size() == oldEdges.size(); -- FIXME oppositeEdges inhibit simple equality check
// assert new HashSet<>(edgeSchedule).equals(new HashSet<>(oldEdges));
return sortedCheckedConditions;
}
protected void createConstantCheck(@NonNull Edge edge, @NonNull OCLExpression checkExpression) {
Role edgeRole = partition.getRole(edge);
assert edgeRole != null;
if (edgeRole.isSpeculated()) {
assert edge.isSuccess();
boolean isInfallible = isInfallible();
boolean isTerminating = isTerminating();
if (isInfallible) { // If cycles are guaranteed not to fail (e.g. Forward2Reverse)
// Speculation code can be omitted.
}
else if (isTerminating) { // If cycles are guaranteed to terminate (e.g. ATL2QVTr containment ascent)
createCheckStatement(checkExpression);
}
else {
QVTruntimeUtil.errPrintln("Speculation code omitted for " + partition);
}
}
else {
createCheckStatement(checkExpression);
}
}
public void synthesize(@NonNull Iterable<@NonNull CheckedCondition> checkedConditions) {
for (@NonNull Edge edge : edgeSchedule) {
assert partition.getRole(edge) != null;;
assert edge.isUnconditional();
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
assert sourceNode.isUnconditional();
Role sourceNodeRole = partition.getRole(sourceNode);
if (sourceNodeRole != null) {
Node targetNode = QVTscheduleUtil.getTargetNode(edge);
assert targetNode.isUnconditional();
Role targetNodeRole = partition.getRole(targetNode);
if (targetNodeRole != null) {
if (edge.isNavigation()) {
NavigationEdge navigationEdge = (NavigationEdge)edge;
Property property = QVTscheduleUtil.getReferredProperty(navigationEdge);
OCLExpression sourceExp = createVariableExp(sourceNode);
Type sourceType = sourceExp.getType();
Type requiredType = property.getOwningClass();
if ((requiredType != null) && !sourceType.conformsTo(getMetamodelManager().getStandardLibrary(), requiredType)) {
String castName = "cast_" + sourceNode.getName(); // FIXME BUG 530033 in a closed world this is always a fail
DeclareStatement castStatement = createCheckedDeclareStatement(castName, sourceExp, requiredType);
sourceExp = helper.createVariableExp(castStatement);
}
OCLExpression source2targetExp = createCallExp(sourceExp, property);
if (targetNode.isNullLiteral()) {
createCheckStatement(source2targetExp, "=", helper.createNullLiteralExp());
}
else if (targetNodeRole.isConstant() && !sourceNodeRole.isNew()) {
// createCheckStatement(source2targetExp);
VariableDeclaration nodeVariable = node2variable.get(targetNode);
/*if (nodeVariable == null) {
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(targetVariableExp, "=", source2targetExp);
}
else*/ if (navigationEdge.isPartial()) {
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(source2targetExp, "includes", targetVariableExp);
}
else if ((targetNode instanceof BooleanLiteralNode) && ((BooleanLiteralNode)targetNode).isBooleanValue()) {
createConstantCheck(edge, source2targetExp);
}
else if (targetNodeRole == Role.CONSTANT_SUCCESS_TRUE) {
createConstantCheck(edge, source2targetExp);
}
else if (nodeVariable == null) {
ExpressionCreator expressionCreator = new ExpressionCreator(BasicPartition2Mapping.this);
ExpressionCreator inlineExpressionCreator = expressionCreator.getInlineExpressionCreator();
OCLExpression targetExpression = inlineExpressionCreator.getExpression(targetNode);
assert targetExpression != null;
createCheckStatement(source2targetExp, "=", targetExpression);
}
else {
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(source2targetExp, "=", targetVariableExp);
}
}
else {
VariableDeclaration nodeVariable = node2variable.get(targetNode);
if (nodeVariable == null) {
createDeclareStatement(targetNode, source2targetExp);
// createCastPredicates(targetNode, declareStatement);
}
else if (navigationEdge.isPartial()) {
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(source2targetExp, "includes", targetVariableExp);
}
else {
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(targetVariableExp, "=", source2targetExp);
}
}
}
else if (edge instanceof PredicateEdge) {
VariableExp sourceVariableExp = getSubexpressionVariableExp(sourceNode);
if (!(targetNode instanceof BooleanLiteralNode)) {
String edgeName = ClassUtil.nonNullState(edge.getName()).trim();
if (edgeName.length() >= 2) {
edgeName = edgeName.substring(1, edgeName.length()-1); // Lose guillemets
}
if ("equals".equals(edgeName)) {
edgeName = "="; // FIXME regularize
}
VariableExp targetVariableExp = getSubexpressionVariableExp(targetNode);
createCheckStatement(sourceVariableExp, edgeName, targetVariableExp);
}
else if (((BooleanLiteralNode)targetNode).isBooleanValue()) {
createConstantCheck(edge, sourceVariableExp);
}
else {
createCheckStatement(sourceVariableExp, "=", helper.createBooleanLiteralExp(false));
}
}
else if (edge instanceof ExpressionEdge) {
getSubexpressionDeclaration(targetNode);
}
}
else {
// SharedEdge
}
}
}
List<@NonNull Subexpression> subexpressions = new ArrayList<>(resultNode2subexpression.values());
Collections.sort(subexpressions);
for (@NonNull Subexpression subexpression : subexpressions) {
Role resultNodeRole = partition.getRole(subexpression.resultNode);
if ((resultNodeRole != null) && !resultNodeRole.isNew() && subexpression.resultNode.isUnconditional()) {
getSubexpressionDeclaration(subexpression.resultNode);
}
}
}
@Override
public @NonNull String toString() {
StringBuilder s = new StringBuilder();
boolean isFirst = true;
for (@NonNull Edge edge : edgeSchedule) {
if (!isFirst) {
s.append("\n");
}
s.append(edge);
isFirst = false;
}
return s.toString();
}
}
private static class ExpressionCreator extends AbstractExtendingQVTbaseVisitor<@NonNull OCLExpression, @NonNull BasicPartition2Mapping>
{
protected final @NonNull QVTimperativeHelper helper;
protected final @NonNull QVTbaseLibraryHelper qvtbaseLibraryHelper;
protected final @NonNull Set<@NonNull Node> multiAccessedNodes = new HashSet<>();
protected final @NonNull Set<@NonNull Node> conditionalNodes = new HashSet<>();
private /*@LazyNonNull*/ ExpressionCreator inlineExpressionCreator = null;
public ExpressionCreator(@NonNull BasicPartition2Mapping context) {
super(context);
this.helper = context.getHelper();
this.qvtbaseLibraryHelper = context.getQVTbaseLibraryHelper();
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<>();
Partition partition = context.getPartition();
for (@NonNull Edge edge : partition.getPartialEdges()) {
Role role = partition.getRole(edge);
if ((role != null) && role.isRealized()) {
analyzeIncomingPath(edge.getEdgeTarget(), unconditionalNodes, conditionalNodes, false);
}
}
conditionalNodes.removeAll(unconditionalNodes);
for (@NonNull Node node : unconditionalNodes) {
int accesses = 0;
for (@NonNull Edge outgoingEdge : QVTscheduleUtil.getOutgoingEdges(node)) {
if (outgoingEdge.isCast() || outgoingEdge.isNavigation() || outgoingEdge.isComputation()) {
accesses++;
}
}
if (accesses > 1) {
multiAccessedNodes.add(node);
}
}
}
private void analyzeIncomingPath(@NonNull Node node, @NonNull Set<Node> unconditionalNodes, @NonNull Set<Node> conditionalNodes, boolean isConditional) {
if ((isConditional ? conditionalNodes : unconditionalNodes).add(node)) {
boolean isIf = node instanceof IfNode; // FIXME better edge typing
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isComputation()) {
boolean isIfThenOrElse = isIf && ("then".equals(edge.getName()) || "else".equals(edge.getName()));
analyzeIncomingPath(edge.getEdgeSource(), unconditionalNodes, conditionalNodes, isConditional || isIfThenOrElse);
}
else if (edge.isCast() || edge.isNavigation()) {
analyzeIncomingPath(edge.getEdgeSource(), unconditionalNodes, conditionalNodes, isConditional);
}
}
return;
}
}
protected @NonNull OCLExpression create(/*@NonNull*/ Node node) {
if (node.isNullLiteral()) {
return helper.createNullLiteralExp();
}
VariableDeclaration theVariable = context.basicGetVariable(node);
if (theVariable == null) {
Element originatingElement = node.getOriginatingElement();
assert originatingElement != null;
OCLExpression initExpression = originatingElement.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 = context.createDeclareStatement(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<>(oldTypedElements.size());
for (@NonNull OCLExpression oldTypedElement : oldTypedElements) {
OCLExpression newTypedElement = create(oldTypedElement);
assert newTypedElement != null;
newTypedElements.add(newTypedElement);
}
return newTypedElements;
}
private @NonNull Variable createIteratorVariable(@NonNull Variable oldVariable) {
String name = oldVariable.getName();
assert name != null;
Type type = oldVariable.getType();
assert type != null;
assert oldVariable.getOwnedInit() == null;
Variable newVariable = helper.createIteratorVariable(name, type, oldVariable.isIsRequired());
Node variableNode = context.getNode(oldVariable);
if (variableNode != null) {
context.addVariable(variableNode, newVariable);
}
return newVariable;
}
private @NonNull List<@NonNull Variable> createIteratorVariables(@NonNull List<@NonNull Variable> oldVariables) {
List<@NonNull Variable> newVariables = new ArrayList<>(oldVariables.size());
for (@NonNull Variable oldVariable : oldVariables) {
Variable newVariable = createIteratorVariable(oldVariable);
newVariables.add(newVariable);
}
return newVariables;
}
private @NonNull Variable createLetVariable(@NonNull Variable oldVariable) {
String name = oldVariable.getName();
assert name != null;
Type type = oldVariable.getType();
assert type != null;
OCLExpression newInit = ClassUtil.nonNullState(create(oldVariable.getOwnedInit()));
Variable newVariable = helper.createLetVariable(name, type, oldVariable.isIsRequired(), newInit);
Node variableNode = context.getNode(oldVariable);
if (variableNode != null) {
context.addVariable(variableNode, newVariable);
}
return newVariable;
}
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 @Nullable OCLExpression createOperationCallExp(@NonNull OperationId operationId, @NonNull OperationNode operationNode) {
OCLExpression asSourceExpression = null;
List<@NonNull OCLExpression> asArgumentExpressions = new ArrayList<>();
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(operationNode)) {
if (edge instanceof ExpressionEdge) {
Node sourceNode = QVTscheduleUtil.getSourceNode(edge); // FIXME ordering/naming/other edges
OCLExpression asExpression = getExpression(sourceNode);
assert asExpression != null;
if (asSourceExpression == null) {
asSourceExpression = asExpression;
}
else {
asArgumentExpressions.add(asExpression);
}
}
}
assert asSourceExpression != null;
@NonNull OCLExpression[] asArguments = asArgumentExpressions.toArray(new @NonNull OCLExpression[asArgumentExpressions.size()]);
return helper.createOperationCallExp(asSourceExpression, operationId.getName(), asArguments);
}
private @NonNull Variable createResultVariable(@NonNull Variable oldVariable) {
String name = oldVariable.getName();
assert name != null;
Type type = oldVariable.getType();
assert type != null;
OCLExpression newInit = ClassUtil.nonNullState(create(oldVariable.getOwnedInit()));
Variable newVariable = helper.createResultVariable(name, type, oldVariable.isIsRequired(), newInit);
Node variableNode = context.getNode(oldVariable);
if (variableNode != null) {
context.addVariable(variableNode, newVariable);
}
return newVariable;
}
private static int depth = 0;
protected @Nullable OCLExpression doBooleanLiteralNode(@NonNull BooleanLiteralNode node) {
return helper.createBooleanLiteralExp(node.isBooleanValue());
}
protected @Nullable OCLExpression doIfNode(@NonNull IfNode node) {
OCLExpression conditionExp = null;
OCLExpression thenExp = null;
OCLExpression elseExp = null;
Parameter conditionParameter = qvtbaseLibraryHelper.getIfConditionParameter();
Parameter thenParameter = qvtbaseLibraryHelper.getIfThenParameter();
Parameter elseParameter = qvtbaseLibraryHelper.getIfElseParameter();
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isExpression() && (edge instanceof OperationParameterEdge)) {
OperationParameterEdge operationParameterEdge = (OperationParameterEdge)edge;
Node expNode = operationParameterEdge.getEdgeSource();
OCLExpression nestedExp = getExpression(expNode);
if (nestedExp == null) {
return null;
}
Parameter parameter = operationParameterEdge.getReferredParameter();
if (parameter == conditionParameter) {
conditionExp = nestedExp;
}
else if (parameter == thenParameter) {
thenExp = nestedExp;
}
else if (parameter == elseParameter) {
elseExp = nestedExp;
}
}
}
if ((conditionExp != null) && (thenExp != null) && (elseExp != null)) {
return helper.createIfExp(conditionExp, thenExp, elseExp);
}
return null;
}
protected @Nullable OCLExpression doNumericLiteralNode(@NonNull NumericLiteralNode node) {
Number numericValue = ClassUtil.nonNullState(node.getNumericValue());
if ((numericValue instanceof Byte) || (numericValue instanceof Integer) || (numericValue instanceof Long) || (numericValue instanceof Short)) {
return helper.createIntegerLiteralExp(numericValue);
}
else {
return helper.createRealLiteralExp(numericValue);
}
}
protected @Nullable OCLExpression doNullLiteralNode(@NonNull NullLiteralNode node) {
return helper.createNullLiteralExp();
}
protected @Nullable OCLExpression doOperationCallNode(@NonNull OperationCallNode node) {
Operation referredOperation = QVTscheduleUtil.getReferredOperation(node);
OCLExpression sourceExp = null;
List<@NonNull Parameter> parameters = QVTbaseUtil.Internal.getOwnedParametersList(referredOperation);
List<@Nullable OCLExpression> argExps = new ArrayList<>(parameters.size());
for (int i = 0; i < parameters.size(); i++) {
argExps.add(null);
}
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isExpression() && (edge instanceof OperationSelfEdge)) {
OperationSelfEdge operationSelfEdge = (OperationSelfEdge)edge;
Node expNode = operationSelfEdge.getEdgeSource();
OCLExpression nestedExp = getExpression(expNode);
if (nestedExp == null) {
return null;
}
sourceExp = nestedExp;
}
else if (edge instanceof OperationParameterEdge) {
OperationParameterEdge operationParameterEdge = (OperationParameterEdge)edge;
Node expNode = operationParameterEdge.getEdgeSource();
OCLExpression nestedExp = getExpression(expNode);
if (nestedExp == null) {
return null;
}
int index = parameters.indexOf(operationParameterEdge.getReferredParameter());
if (0 <= index) {
OCLExpression oldExpression = argExps.set(index, nestedExp);
assert oldExpression == null;
}
}
}
for (OCLExpression exp : argExps) {
if (exp == null) {
return null;
}
}
if (sourceExp != null) {
return helper.createOperationCallExp(sourceExp, referredOperation, ClassUtil.nullFree(argExps));
}
return null;
}
protected @Nullable OCLExpression doStringLiteralNode(@NonNull StringLiteralNode node) {
return helper.createStringLiteralExp(ClassUtil.nonNullState(node.getStringValue()));
}
public @Nullable OCLExpression getExpression(@NonNull Node node) {
if (++depth > 25) {
throw new IllegalStateException();
}
try {
// if (node.isNullLiteral()) {
// return helper.createNullLiteralExp();
// }
VariableDeclaration variable = context.basicGetVariable(node);
if (variable != null) {
assert !node.isNullLiteral(); // null should not be cached in a variable
return PivotUtil.createVariableExp(variable);
}
if (node.isOperation()) {
// FIXME phase out use of originatingElement and use a Visitor now that the Node hierarchy is more relevant
Element originatingElement = node.basicGetOriginatingElement();
if (originatingElement instanceof CollectionTemplateExp) { // The CollectionTemplateExp synthesis has already identified the necessary operations
OperationCallNode operationCallNode = (OperationCallNode)node;
Operation operation = operationCallNode.getReferredOperation();
return createOperationCallExp(operation.getOperationId(), operationCallNode);
}
else if (originatingElement != null) {
return originatingElement.accept(getInlineExpressionCreator());
}
else if (node instanceof BooleanLiteralNode) {
return doBooleanLiteralNode((BooleanLiteralNode)node);
}
else if (node instanceof IfNode) {
return doIfNode((IfNode)node);
}
else if (node instanceof NullLiteralNode) {
return doNullLiteralNode((NullLiteralNode)node);
}
else if (node instanceof NumericLiteralNode) {
return doNumericLiteralNode((NumericLiteralNode)node);
}
else if (node instanceof OperationCallNode) {
return doOperationCallNode((OperationCallNode)node);
}
else if (node instanceof StringLiteralNode) {
return doStringLiteralNode((StringLiteralNode)node);
}
else {
throw new UnsupportedOperationException();
}
}
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isExpression()) {
Node expNode = edge.getEdgeSource();
OCLExpression clonedElement = create(expNode);
if (clonedElement instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)clonedElement).getReferredVariable();
if (referredVariable instanceof Variable) {
context.addVariable(node, referredVariable);
}
}
return clonedElement;
}
}
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
assert !edge.isCast();
if (edge.isNavigation()) {
NavigationEdge navigationEdge = (NavigationEdge)edge;
Role edgeRole = QVTscheduleUtil.getEdgeRole(edge);
if (edgeRole == Role.LOADED) {
OCLExpression source = getExpression(edge.getEdgeSource());
if (source != null) {
return helper.createNavigationCallExp(source, QVTscheduleUtil.getReferredProperty(navigationEdge));
}
}
else if (edgeRole == Role.PREDICATED) {
OCLExpression source = create(edge.getEdgeSource());
return helper.createNavigationCallExp(source, QVTscheduleUtil.getReferredProperty(navigationEdge));
}
}
else {
// SharedEdge
}
}
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isExpression()) {
OCLExpression source = create(edge.getEdgeSource());
return source;
}
}
return null;
}
finally {
--depth;
}
}
public @NonNull ExpressionCreator getInlineExpressionCreator() {
ExpressionCreator inlineExpressionCreator2 = inlineExpressionCreator ;
if (inlineExpressionCreator2 == null) {
inlineExpressionCreator = inlineExpressionCreator2 = new InlineExpressionCreator(context);
}
return inlineExpressionCreator2;
}
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 NewStatement) {
return true;
}
}
}
return false;
}
@Override
public String toString() {
return getClass().getSimpleName() + " " + context.getPartition();
}
@Override
public @NonNull OCLExpression visiting(@NonNull Visitable visitable) {
throw new UnsupportedOperationException(getClass().getSimpleName() + ": " + visitable.getClass().getSimpleName());
}
// public boolean isConditional(@NonNull Node node) {
// return conditionalNodes.contains(node);
// }
@Override
public @NonNull OCLExpression visitCollectionLiteralExp(@NonNull CollectionLiteralExp pCollectionLiteralExp) {
List<@NonNull CollectionLiteralPart> clonedParts = new ArrayList<>();
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 visitEnumLiteralExp(@NonNull EnumLiteralExp pEnumLiteralExp) {
return EcoreUtil.copy(pEnumLiteralExp);
}
@Override
public @NonNull OCLExpression visitIfExp(@NonNull IfExp pIfExp) {
MetamodelManager metamodelManager = helper.getEnvironmentFactory().getMetamodelManager();
ExpressionCreator inlineExpressionCreator = getInlineExpressionCreator();
return ((PivotMetamodelManager)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 = createIteratorVariables(ClassUtil.nullFree(pIterateExp.getOwnedIterators()));
Variable result = createResultVariable(ClassUtil.nonNull(pIterateExp.getOwnedResult()));
Iteration referredIteration = context.createOperation(QVTrelationUtil.getReferredIteration(pIterateExp));
assert referredIteration != null;
OCLExpression iBody = getInlineExpressionCreator().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 = createIteratorVariables(ClassUtil.nullFree(pIteratorExp.getOwnedIterators()));
Iteration referredIteration = context.createOperation(QVTrelationUtil.getReferredIteration(pIteratorExp));
assert referredIteration != null;
OCLExpression iBody = getInlineExpressionCreator().create(pIteratorExp.getOwnedBody());
assert iBody != null;
return helper.createIteratorExp(iSource, referredIteration, iIterators, iBody);
}
@Override
public @NonNull OCLExpression visitLetExp(@NonNull LetExp pLetExp) {
Variable asVariable = createLetVariable(ClassUtil.nonNull(pLetExp.getOwnedVariable()));
OCLExpression asInExpression = create(pLetExp.getOwnedIn());
assert asInExpression != null;
return helper.createLetExp(asVariable, asInExpression);
}
@Override
public @NonNull OCLExpression visitMapLiteralExp(@NonNull MapLiteralExp pMapLiteralExp) {
List<@NonNull MapLiteralPart> clonedParts = new ArrayList<>();
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 = context.createOperation(QVTrelationUtil.getReferredOperation(pOperationCallExp));
assert referredOperation != null;
if ((iSource == null) && (referredOperation instanceof Function)) {
StandardLibrary standardLibrary = helper.getEnvironmentFactory().getStandardLibrary();
VariableDeclaration thisVariable = QVTbaseUtil.getContextVariable(standardLibrary, context.getTransformation());
iSource = PivotUtil.createVariableExp(thisVariable);
}
return helper.createOperationCallExp(iSource, referredOperation, iArguments);
}
@Override
public @NonNull OCLExpression visitNavigationCallExp(@NonNull NavigationCallExp pNavigationCallExp) {
OCLExpression iSource = createNonNull(pNavigationCallExp.getOwnedSource());
Property referredProperty = PivotUtil.getReferredProperty(pNavigationCallExp);
return helper.createNavigationCallExp(iSource, referredProperty);
}
@Override
public @NonNull OCLExpression visitPrimitiveLiteralExp(@NonNull PrimitiveLiteralExp pPrimitiveLiteralExp) {
return EcoreUtil.copy(pPrimitiveLiteralExp);
}
@Override
public @NonNull OCLExpression visitShadowExp(@NonNull ShadowExp pShadowExp) {
List<@NonNull ShadowPart> clonedParts = new ArrayList<>();
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<>();
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 -- should not be invoked; results in use of input not output variable
// public @NonNull OCLExpression visitVariable(@NonNull Variable pVariable) {
// return helper.createVariableExp(pVariable);
// }
@Override
public @NonNull OCLExpression visitVariableExp(@NonNull VariableExp pVariableExp) {
VariableDeclaration pVariable = pVariableExp.getReferredVariable();
Node node = context.getNode(pVariable);
if (node == null) {
StandardLibrary standardLibrary = helper.getEnvironmentFactory().getStandardLibrary();
Transformation pTransformation = QVTbaseUtil.getContainingTransformation(pVariableExp);
Variable pThisVariable = QVTbaseUtil.getContextVariable(standardLibrary, pTransformation);
if (pVariableExp.getReferredVariable() == pThisVariable) {
VariableDeclaration iThisVariable = QVTbaseUtil.getContextVariable(standardLibrary, context.getTransformation());
return PivotUtil.createVariableExp(iThisVariable);
}
}
if (node != null) {
VariableDeclaration iVariable = context.basicGetVariable(node);
assert iVariable != null;
return PivotUtil.createVariableExp(iVariable);
}
else {
QVTruntimeUtil.errPrintln("Creating unexpected variable for " + pVariable + " in " + context.getPartition());
Type variableType = pVariable.getType();
assert variableType != null;
String safeName = context.getSafeName(ClassUtil.nonNullState(pVariable.getName()));
DeclareStatement iVariable = helper.createDeclareStatement(safeName, variableType, pVariable.isIsRequired(), helper.createNullLiteralExp());
context.getMapping().getOwnedStatements().add(iVariable);
// Variable oldVariable = node2variable.put(node, iVariable);
// assert oldVariable == null;
return PivotUtil.createVariableExp(iVariable);
}
}
}
private static class InlineExpressionCreator extends ExpressionCreator
{
private int debugDepth = 0;
private InlineExpressionCreator(@NonNull BasicPartition2Mapping context) {
super(context);
}
@Override
public @NonNull OCLExpression create(/*@NonNull*/ Node node) {
try {
if (++debugDepth > 100) {
throw new UnsupportedOperationException();
}
if (node.isNullLiteral()) {
return helper.createNullLiteralExp();
}
VariableDeclaration theVariable = context.basicGetVariable(node);
if (theVariable != null) {
return PivotUtil.createVariableExp(theVariable);
}
VariableDeclaration variable = node.basicGetOriginatingVariable(); // FIXME This fallback should be obsolete
if (variable instanceof Variable) {
OCLExpression ownedInit = ((Variable)variable).getOwnedInit();
if (ownedInit == null) {
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) { // FIXME this can pick a downstream rather than upstream edge
assert !edge.isCast();
if (edge.isExpression() && RegionHelper.EQUALS_NAME.equals(edge.getName())) { // ?? always an Equals(Predicate)Edge
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
return create(sourceNode); //createBottomVariable(node, helper.createNullLiteralExp()); // FIXME is this possible?
}
else if (edge.isNavigation()) {
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
OCLExpression sourceExpression = create(sourceNode);
Property referredProperty = QVTscheduleUtil.getReferredProperty((NavigationEdge) edge);
return helper.createNavigationCallExp(sourceExpression, referredProperty);
}
}
}
else {
return ownedInit.accept(this);
}
}
else {
Element originatingElement = node.getOriginatingElement();
return originatingElement.accept(this);
}
throw new UnsupportedOperationException();
}
finally {
debugDepth--;
}
}
}
private class Subexpression implements Comparable<@NonNull Subexpression>
{
/**
* The subexpression result
*/
private final @NonNull OperationNode resultNode;
/**
* External nodes used within the subexpression
*/
private final @NonNull Set<@NonNull Node> inputNodes = new HashSet<>();
/**
* External nodes used within the subexpression
*/
private final @NonNull Set<@NonNull Node> unconditionalInputNodes = new HashSet<>();
/**
* Nodes within the subexpression
*/
private final @NonNull Set<@NonNull Node> contentNodes = new HashSet<>();
private @Nullable Integer cost = null;
public Subexpression(@NonNull OperationNode resultNode) {
this.resultNode = resultNode;
assert resultNode.isUnconditional();
}
public void analyze(@NonNull Set<@NonNull OperationNode> subexpressionResults) {
computeSubexpressionContent(resultNode, subexpressionResults);
}
@Override
public int compareTo(@NonNull Subexpression e2) {
Subexpression e1 = this;
int d1 = e1.getCost();
int d2 = e2.getCost();
if (d1 != d2) {
return d1 - d2;
}
return ClassUtil.safeCompareTo(e1.resultNode.getDisplayName(), e2.resultNode.getDisplayName());
}
private void computeSubexpressionContent(@NonNull Node node, @NonNull Set<@NonNull OperationNode> subexpressionResults) {
if (contentNodes.add(node)) {
Role resultNodeRole = partition.getRole(resultNode);
assert resultNodeRole != null;
node2subexpression.put(node, this);
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
Role edgeRole = partition.getRole(edge);
if (edgeRole != null) {
// if (edge.isUnconditional()) {
Node sourceNode = edge.getEdgeSource();
Role sourceNodeRole = partition.getRole(sourceNode);
if (sourceNodeRole != null) {
if (subexpressionResults.contains(sourceNode)) {
if (sourceNodeRole.isOld() || (!edge.isSecondary() && resultNodeRole.isNew())) {
inputNodes.add(sourceNode);
if (edge.isUnconditional() && sourceNode.isUnconditional()) {
unconditionalInputNodes.add(sourceNode);
}
// edge2subexpression.put(edge, this);
}
}
else if (sourceNode.isExpression()) {
node2subexpression.put(sourceNode, this);
edge2subexpression.put(edge, this);
computeSubexpressionContent(sourceNode, subexpressionResults);
}
else if (!sourceNode.isUnconditional()) {
node2subexpression.put(sourceNode, this);
edge2subexpression.put(edge, this);
computeSubexpressionContent(sourceNode, subexpressionResults);
}
else {
if (sourceNodeRole.isOld() || resultNodeRole.isNew()) {
inputNodes.add(sourceNode);
if (edge.isUnconditional() && sourceNode.isUnconditional()) {
unconditionalInputNodes.add(sourceNode);
}
// edge2subexpression.put(edge, this);
}
}
}
// }
}
}
}
}
public int getCost() {
Integer cost2 = cost;
if (cost2 == null) {
cost2 = reachabilityForest.getCost(resultNode);
if (cost2 == null) { // Can happen for REALIZED results
int inputCost = 0;
for (@NonNull Node inputNode : inputNodes) {
Subexpression inputSubexpression = resultNode2subexpression.get(inputNode);
if (inputSubexpression != null) {
inputCost = Math.max(inputCost, inputSubexpression.getCost()+1);
}
}
cost2 = inputCost;
}
cost = cost2;
}
return cost2;
}
@Override
public @NonNull String toString() {
return String.valueOf(resultNode);
}
}
protected final @NonNull MappingPartitionAnalysis<?> partitionAnalysis;
protected final @NonNull RegionAnalysis regionAnalysis;
/**
* Lazily computed closure of all preceding nodes, icluding the final node, of each node.
*/
private @Nullable Map<@NonNull Node, @NonNull Set<@NonNull Node>> node2precedingNodeClosure = null;
/**
* Map from each subexpression result node to its contents.
*/
private final @NonNull Map<@NonNull OperationNode, @NonNull Subexpression> resultNode2subexpression;
/**
* Map from each subexpression node to its contents.
*/
private final @NonNull Map<@NonNull Node, @NonNull Subexpression> node2subexpression = new HashMap<>();
/**
* Map from each subexpression edge to its contents.
*/
private final @NonNull Map<@NonNull Edge, @NonNull Subexpression> edge2subexpression = new HashMap<>();
/**
* The selected head from each head group that is actually passed. Other heads are computed.
*/
private final @NonNull List<@NonNull Node> headNodes = new ArrayList<>();
/**
* The subset of possible guard nodes that all callers can pass.
*/
private final @NonNull List<@NonNull Node> guardNodes = new ArrayList<>();
/**
* Mapping from the scheduled Nodes to their QVTi variables.
*/
private final @NonNull Map<@NonNull Node, @NonNull VariableDeclaration> node2variable = new HashMap<>();
/**
* The mechanisms to reach required nodes.
*/
private final @NonNull ReachabilityForest reachabilityForest;
/**
* The failure mechanisms.
*/
private final @NonNull CheckedConditionAnalysis checkedConditionAnalysis;
public BasicPartition2Mapping(@NonNull QVTs2QVTiVisitor visitor, @NonNull MappingPartitionAnalysis<?> partitionAnalysis) {
super(visitor, partitionAnalysis.getPartition());
this.partitionAnalysis = partitionAnalysis;
this.regionAnalysis = scheduleManager.getRegionAnalysis(QVTscheduleUtil.getRegion(partition));
this.reachabilityForest = partitionAnalysis.getReachabilityForest();
this.checkedConditionAnalysis = new CheckedConditionAnalysis(partitionAnalysis, scheduleManager);
StringBuilder s = TransformationPartitioner.PROPERTY_OBSERVE.isActive() ? new StringBuilder() : null;
if (s != null) {
s.append("[" + partition.getPassRangeText() + "] " + partition.getName());
}
checkedConditionAnalysis.computeCheckedProperties(s);
if (s != null) {
TransformationPartitioner.PROPERTY_OBSERVE.println(s.toString());
}
this.resultNode2subexpression = computeSubexpressions();
//
// Gather the subexpression contents.
//
Set<@NonNull OperationNode> subexpressionResults = resultNode2subexpression.keySet();
for (@NonNull Subexpression subexpression : resultNode2subexpression.values()) {
subexpression.analyze(subexpressionResults);
}
}
/* private @NonNull Iterable<@NonNull Node> getReachabilityRootNodes() {
//
// The zero-cost nodes are the head nodes ...
//
List<@NonNull Node> zeroCostNodes = Lists.newArrayList(partition.getHeadNodes());
//
// ... and the no-input constant nodes
//
for (@NonNull Node node : partition.getPartialNodes()) {
if (node.isOperation()) {
if (node.isConstant()) {
boolean hasNoComputationInputs = true;
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isComputation()) {
hasNoComputationInputs = false;
break;
}
}
if (hasNoComputationInputs) {
zeroCostNodes.add(node);
}
}
}
}
return zeroCostNodes;
} */
/**
* Return the navigable edges that may be used by to locate nodes by this partition.
* The default implementation returns all old primary navigable edges
* and all already realized navigable edges
*/
protected @NonNull Iterable<@NonNull NavigableEdge> getAvailableNavigableEdges() {
Set<@NonNull NavigableEdge> oldEdges = new HashSet<>();
for (@NonNull Edge edge : partition.getPartialEdges()) {
assert !edge.isCast();
Role edgeRole = partition.getRole(edge);
assert edgeRole != null;
if (edgeRole.isOld() && edge.isNavigation() /*&& edge.isUnconditional()*/) {
Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
Role sourceNodeRole = partition.getRole(sourceNode);
assert sourceNodeRole != null;
if (sourceNodeRole.isOld()){
Node targetNode = QVTscheduleUtil.getTargetNode(edge);
Role targetNodeRole = partition.getRole(targetNode);
assert targetNodeRole != null;
if (targetNodeRole.isOld()) {
oldEdges.add((NavigableEdge) edge);
}
}
}
}
// List<@NonNull Edge> sortedEdges = new ArrayList<>(oldEdges);
// Collections.sort(sortedEdges, reachabilityForest.getEdgeCostComparator());
return oldEdges;
}
public void addVariable(@NonNull Node node, @NonNull VariableDeclaration variableDeclaration) {
@SuppressWarnings("unused")
VariableDeclaration oldVariableDeclaration = node2variable.put(node, variableDeclaration);
// assert oldVariableDeclaration == null; -- FIXME QVTc test overwrites
}
public @Nullable VariableDeclaration basicGetVariable(@NonNull Node node) {
return node2variable.get(node);
}
/**
* Return all subexpressions and their content. A subexpression is an OperationNode whose value is consumed by
* one (or more) PatternNodes or by two (or more) OperationNodes.
*/
private @NonNull Map<@NonNull OperationNode, @NonNull Subexpression> computeSubexpressions() {
Map<@NonNull OperationNode, @NonNull Subexpression> resultNode2subexpression = new HashMap<>();
//
// Identify the subexpression result nodes
//
for (@NonNull Node node : partition.getPartialNodes()) {
Role nodeRole = partition.getRole(node);
if (nodeRole != null) {
if (node.isOperation() && node.isUnconditional() && !node.isPrimitive()) {
OperationNode resultNode = (OperationNode) node;
Edge firstEdge = null;
boolean isSubexpression = false;
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
Role edgeRole = partition.getRole(edge);
if ((edgeRole != null) && edgeRole.isNew() && !edge.isSecondary()) {
Node edgeSource = edge.getSourceNode();
if (edgeSource.isPattern()) {
resultNode2subexpression.put(resultNode, new Subexpression(resultNode));
isSubexpression = true;
break;
}
}
}
if (!isSubexpression) {
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(node)) {
Role edgeRole = partition.getRole(edge);
if (edgeRole != null) {
Node edgeTarget = edge.getTargetNode();
if (edgeTarget.isPattern() /*|| edgeTarget.isTrue()*/) {
resultNode2subexpression.put(resultNode, new Subexpression(resultNode));
break;
}
if (firstEdge == null) {
firstEdge = edge;
}
else {
resultNode2subexpression.put(resultNode, new Subexpression(resultNode));
break;
}
}
}
}
}
}
}
return resultNode2subexpression;
}
/**
* Create accumulation assignments for connections.
*/
private void createAddStatements() {
if (connection2variable != null) {
for (@NonNull NodeConnection connection : connection2variable.keySet()) {
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(connection);
if (classDatum.isDataType()) {
boolean hasTargetEdges = false;
for (@NonNull ConnectionEnd connectionEnd : connection.getTargetConnectionEnds(partition)) {
Iterable<@NonNull Edge> edges = QVTscheduleUtil.getOutgoingEdges((Node) connectionEnd);
if (!Iterables.isEmpty(edges)) {
hasTargetEdges = true;
break;
}
}
if (hasTargetEdges) {
continue;
}
}
Node sourceNode = connection.getSource(partition);
OCLExpression variableExpression = createVariableExp(sourceNode);
ConnectionVariable connectionVariable = connection2variable.get(connection);
assert connectionVariable != null;
createAddStatement(connectionVariable, variableExpression);
}
}
}
private void createCallStatements(@NonNull Map<@NonNull Partition, @NonNull Map<@NonNull Node, @NonNull Node>> calls) {
List<@NonNull MappingStatement> mappingStatements = new ArrayList<>();
Map<@NonNull LoopVariable, @NonNull OCLExpression> loopVariables = null;
for (Map.Entry<@NonNull Partition, @NonNull Map<@NonNull Node, @NonNull Node>> entry : calls.entrySet()) {
@NonNull Partition calledPartition = entry.getKey();
AbstractPartition2Mapping calledRegion2Mapping = visitor.getPartition2Mapping(calledPartition);
List<@NonNull MappingParameterBinding> mappingParameterBindings = new ArrayList<>();
for (Map.Entry<@NonNull Node, @NonNull Node> entry2 : entry.getValue().entrySet()) {
@NonNull Node sourceNode = entry2.getKey();
@NonNull Node targetNode = entry2.getValue();
OCLExpression sourceExpression = createVariableExp(sourceNode);
Type type = sourceExpression.getType();
if (type instanceof CollectionType) {
if (loopVariables == null) {
loopVariables = new HashMap<>();
}
Type elementType = ((CollectionType)type).getElementType();
assert elementType != null;
LoopVariable loopVariable = helper.createLoopVariable(getSafeName("loop" + loopVariables.size()), elementType);//, true, sourceExpression);
loopVariables.put(loopVariable, sourceExpression);
// sourceExpression = PivotUtil.createVariableExp(loopVariable);
VariableDeclaration guardVariable = calledRegion2Mapping.getGuardVariable(targetNode);
mappingParameterBindings.add(helper.createLoopParameterBinding((GuardParameter) guardVariable, loopVariable));
}
else {
VariableDeclaration guardVariable = calledRegion2Mapping.getGuardVariable(targetNode);
mappingParameterBindings.add(helper.createSimpleParameterBinding((SimpleParameter) guardVariable, sourceExpression));
}
}
Collections.sort(mappingParameterBindings, QVTimperativeUtil.MappingParameterBindingComparator.INSTANCE);
MappingStatement mappingCallStatement = calledRegion2Mapping.createMappingCall(mappingParameterBindings);
if (loopVariables != null) {
for (Map.Entry<@NonNull LoopVariable, @NonNull OCLExpression> loopEntry : loopVariables.entrySet()) {
@NonNull LoopVariable loopVariable = loopEntry.getKey();
@NonNull OCLExpression loopSource = loopEntry.getValue();
mappingCallStatement = helper.createMappingLoop(loopSource, loopVariable, mappingCallStatement);
}
}
mappingStatements.add(mappingCallStatement);
}
mapping.getOwnedStatements().addAll(mappingStatements);
}
private @NonNull CheckStatement createCheckStatement(@NonNull OCLExpression booleanExpression) {
CheckStatement checkStatement = helper.createCheckStatement(booleanExpression);
mapping.getOwnedStatements().add(checkStatement);
return checkStatement;
}
private @NonNull CheckStatement createCheckStatement(@NonNull OCLExpression firstExpression, @NonNull String operatorName, @NonNull OCLExpression secondExpression) {
OCLExpression booleanExpression = helper.createOperationCallExp(firstExpression, operatorName, secondExpression);
CheckStatement checkStatement = createCheckStatement(booleanExpression);
return checkStatement;
}
private @NonNull DeclareStatement createCheckedDeclareStatement(@NonNull String name, @NonNull OCLExpression sourceExp, @NonNull Type requiredType) {
String safeName = getSafeName(name);
DeclareStatement castStatement = helper.createDeclareStatement(safeName, requiredType, true, sourceExp);
mapping.getOwnedStatements().add(castStatement);
return castStatement;
}
private void createClassSetStatement(@Nullable StringBuilder s, @NonNull NavigableEdge edge) {
if (edge instanceof NavigationEdge) {
NavigationEdge navigationEdge = (NavigationEdge)edge;
Node sourceNode = edge.getEdgeSource();
Node targetNode = edge.getEdgeTarget();
Property property = QVTscheduleUtil.getReferredProperty(navigationEdge);
boolean isNotify = connectionManager.isHazardousWrite(s, navigationEdge);
Property setProperty;
VariableDeclaration slotVariable;
OCLExpression targetVariableExp;
SetStatement setStatement;
boolean isPartial;
if (/*!isPartial &&*/ property.isIsImplicit()) {
slotVariable = getVariable(targetNode);
setProperty = QVTrelationUtil.getOpposite(property);
targetVariableExp = createVariableExp(sourceNode);
isPartial = setProperty.isIsMany();
}
else {
slotVariable = getVariable(sourceNode);
setProperty = property;
targetVariableExp = createVariableExp(targetNode);
isPartial = edge.isPartial();
}
setStatement = helper.createSetStatement(slotVariable, setProperty, targetVariableExp, isPartial, isNotify);
mapping.getOwnedStatements().add(setStatement);
}
else {
// SharedEdge
}
}
private @NonNull DeclareStatement createDeclareStatement(@NonNull Node node, @NonNull OCLExpression initExpression) {
Type variableType = node.getClassDatum().getPrimaryClass();
assert variableType != null;
boolean isRequired = node.isMatched() && node.isRequired();
if (initExpression.isIsRequired()) {
isRequired = true;
}
String safeName = getSafeName(node);
DeclareStatement newVariable = helper.createDeclareStatement(safeName, variableType, isRequired, initExpression);
mapping.getOwnedStatements().add(newVariable);
VariableDeclaration oldVariable = node2variable.put(node, newVariable);
assert oldVariable == null;
return newVariable;
}
private @NonNull GuardParameter createGuardParameter(@NonNull Node guardNode) {
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(guardNode);
Type variableType = guardNode.getClassDatum().getPrimaryClass();
ImperativeTypedModel iTypedModel = ClassUtil.nonNullState(visitor.getQVTiTypedModel(classDatum.getReferredTypedModel()));
GuardParameter guardParameter = helper.createGuardParameter(getSafeName(guardNode), iTypedModel, variableType, true);
Property successProperty = null;
Property globalSuccessProperty = scheduleManager.basicGetGlobalSuccessProperty(guardNode);
if (globalSuccessProperty != null) {
NavigableEdge globalSuccessEdge = guardNode.getOutgoingNavigableEdge(globalSuccessProperty);
if (globalSuccessEdge != null) {
Role globalSuccessEdgeRole = partition.getRole(globalSuccessEdge);
if (globalSuccessEdgeRole != null) {
Node globalSuccessNode = QVTscheduleUtil.getTargetNode(globalSuccessEdge);
if (globalSuccessNode.isSuccess() && !globalSuccessEdgeRole.isPredicated()) { // Skip predicated success
assert globalSuccessEdgeRole.isRealized();
successProperty = globalSuccessProperty;
// assert !isHazardousWrite(globalSuccessEdge);
}
}
}
}
Property localSuccessProperty = scheduleManager.basicGetLocalSuccessProperty(guardNode);
if (localSuccessProperty != null) {
NavigableEdge localSuccessEdge = guardNode.getOutgoingNavigableEdge(localSuccessProperty);
if (localSuccessEdge != null) {
Role localSuccessEdgeRole = partition.getRole(localSuccessEdge);
if (localSuccessEdgeRole != null) {
Node localSuccessNode = QVTscheduleUtil.getTargetNode(localSuccessEdge);
if (localSuccessNode.isSuccess() && !localSuccessEdgeRole.isPredicated()) { // Skip predicated local-success
assert localSuccessEdgeRole.isRealized();
assert successProperty == null;
successProperty = localSuccessProperty;
// assert !isHazardousWrite(localSuccessEdge);
}
}
}
}
if (successProperty != null) {
guardParameter.setSuccessProperty(successProperty);
}
mapping.getOwnedMappingParameters().add(guardParameter);
VariableDeclaration oldVariable = node2variable.put(guardNode, guardParameter);
assert oldVariable == null;
return guardParameter;
}
/**
* 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 : QVTscheduleUtil.getHeadNodes(partition)) { // FIXME Move best bead selection to QVTs2QVTs so that diagrams show best head
if (!headNode.isDependency()) {
Node bestHeadNode = null;
Iterable<@NonNull Node> callingSources = connectionManager.getPassedBindingSources(headNode);
if (!Iterables.isEmpty(callingSources)) {
bestHeadNode = headNode;
}
for (@NonNull Node callingSource : callingSources) {
headCallingRegions.add(QVTscheduleUtil.getOwningRegion(callingSource));
}
if (bestHeadNode != null) {
headNodes.add(bestHeadNode);
}
else {
visitor.addProblem(CompilerUtil.createPartitionError(partition, "No best head"));
}
}
}
guardNodes.addAll(headNodes);
/* for (@NonNull SharedEdge sharedEdge : partitionAnalysis.getPredicatedSharedEdges()) {
Node targetNode = QVTscheduleUtil.getTargetNode(sharedEdge);
boolean hasOutgoingEdges = false;
for (@NonNull Edge outgoingEdge : QVTscheduleUtil.getOutgoingEdges(targetNode)) {
Role edgeRole = partition.getRole(outgoingEdge);
if (edgeRole != null) {
hasOutgoingEdges = true;
}
}
if (hasOutgoingEdges) {
assert !guardNodes.contains(targetNode);
guardNodes.add(targetNode);
}
} */
Collections.sort(guardNodes, NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull Node guardNode : guardNodes) {
if (!guardNode.isDependency()) {
createGuardParameter(guardNode);
}
}
//
// Create any connectionVariable guards
//
createAppendParameters();
}
private void createObservedProperties() {
String name = getPartition().getName();
if ("complexAttributePrimitiveAttributes«local»".equals(name)) {
getClass();
}
Set<@NonNull Property> allCheckedProperties = checkedConditionAnalysis.getAllCheckedProperties();
if (!allCheckedProperties.isEmpty()) {
//
// Ideally we could install each observed property as it is actually used. But
// this needs to be coded in many places.
//
for (Statement asStatement : mapping.getOwnedStatements()) {
if (asStatement instanceof ObservableStatement) {
List<Property> observedProperties = ((ObservableStatement)asStatement).getObservedProperties();
for (EObject eObject : new TreeIterable(asStatement, false)) {
if (eObject instanceof PropertyCallExp) {
Property property = PivotUtil.getReferredProperty((PropertyCallExp) eObject);
if (allCheckedProperties.contains(property) && !observedProperties.contains(property)) {
observedProperties.add(property);
}
}
else if (eObject instanceof OppositePropertyCallExp) {
Property property = PivotUtil.getReferredProperty((NavigationCallExp) eObject).getOpposite();
if (allCheckedProperties.contains(property) && !observedProperties.contains(property)) {
observedProperties.add(property);
}
}
}
}
}
}
}
@SuppressWarnings("unchecked")
public <T extends Operation> @NonNull T createOperation(@NonNull T operation) {
Operation newOperation = visitor.create(operation);
assert newOperation != null;
return (@NonNull T) newOperation;
}
/**
* Determine a traversal order for the old edges then synthesize the patttern matching statements.
*/
private void createPatternMatch() {
if (mapping.isIsAbstract()) {
// mapping.getOwnedStatements().add(createCheckStatement(helper.createBooleanLiteralExp(false))); // FIXME add a message
OldEdgeSchedule oldSchedule = new OldEdgeSchedule();
Iterable<@NonNull CheckedCondition> checkedConditions = oldSchedule.analyze();
oldSchedule.synthesize(checkedConditions);
}
else {
OldEdgeSchedule oldSchedule = new OldEdgeSchedule();
Iterable<@NonNull CheckedCondition> checkedConditions = oldSchedule.analyze();
oldSchedule.synthesize(checkedConditions);
}
}
private void createPropertyAssignments() {
StringBuilder s = TransformationPartitioner.PROPERTY_NOTIFY.isActive() ? new StringBuilder() : null;
if (s != null) {
s.append("[" + partition.getPassRangeText() + "] " + partition.getName());
}
Map<@NonNull Node, @NonNull List<@NonNull NavigationEdge>> classAssignments = null;
List<@NonNull NavigableEdge> navigableEdges = new ArrayList<>();
for (@NonNull Edge edge : partition.getPartialEdges()) {
if (edge.isNavigation()) {
Role edgeRole = partition.getRole(edge);
if ((edgeRole != null) && edgeRole.isRealized()) {
navigableEdges.add((NavigableEdge)edge);
}
}
}
Iterable<@NonNull NavigableEdge> sortedEdges = NavigationEdgeSorter.getSortedAssignments(navigableEdges);
for (@NonNull NavigableEdge edge : sortedEdges) {
if (edge instanceof NavigationEdge) {
NavigationEdge navigationEdge = (NavigationEdge)edge;
Node sourceNode = edge.getEdgeSource();
Node targetNode = edge.getEdgeTarget();
if (targetNode.isSuccess()) {} // SuccessNode has a 'magic' automatic assignment
else if (targetNode.isDataType()) {
VariableDeclaration asVariable = getVariable(sourceNode);
Property property = QVTscheduleUtil.getReferredProperty(navigationEdge);
ExpressionCreator expressionCreator = new ExpressionCreator(this);
OCLExpression valueExp = expressionCreator.getExpression(targetNode);
if (valueExp == null) {
ExpressionCreator expressionCreator2 = new ExpressionCreator(this);
valueExp = expressionCreator2.getExpression(targetNode); // FIXME debugging
}
if (valueExp != null) {
boolean isNotify = connectionManager.isHazardousWrite(s, navigationEdge);
SetStatement setStatement = helper.createSetStatement(asVariable, property, valueExp, edge.isPartial(), isNotify);
// addObservedProperties(setStatement);
mapping.getOwnedStatements().add(setStatement);
}
else {
QVTruntimeUtil.errPrintln("No assignment in " + this + " to " + asVariable + "." + property);
}
}
else {
if (classAssignments == null) {
classAssignments = new HashMap<>();
}
List<@NonNull NavigationEdge> edges = classAssignments.get(sourceNode);
if (edges == null) {
edges = new ArrayList<>();
classAssignments.put(sourceNode, edges);
}
edges.add(navigationEdge);
}
}
else {
// SharedEdge
}
}
if (classAssignments != null) {
pruneClassAssignments(classAssignments);
Set<@NonNull NavigationEdge> classAssignmentEdges = new HashSet<>();
for (@NonNull List<@NonNull NavigationEdge> values : classAssignments.values()) {
classAssignmentEdges.addAll(values);
}
for (@NonNull NavigableEdge edge : sortedEdges) {
if (classAssignmentEdges.contains(edge)) {
createClassSetStatement(s, edge);
}
}
}
// @SuppressWarnings("null")
// @NonNull EList<@NonNull Statement> statements = mapping.getOwnedStatements();
// ECollections.sort(statements, new StatementComparator(statements));
if (s != null) {
TransformationPartitioner.PROPERTY_NOTIFY.println(s.toString());
}
}
/* private void createRealizedIncludesAssignments() {
List<@NonNull Edge> realizedIncludesEdges = null;
for (@NonNull Edge edge : region.getRealizedEdges()) {
// if (QVTscheduleUtil.isRealizedIncludes(edge)) {
// if (realizedIncludesEdges == null) {
// realizedIncludesEdges = new ArrayList<>();
// }
// realizedIncludesEdges.add(edge);
// }
}
if (realizedIncludesEdges != null) {
if (realizedIncludesEdges.size() > 1) {
Collections.sort(realizedIncludesEdges, ToStringComparator.INSTANCE);
}
for (@NonNull Edge edge : realizedIncludesEdges) {
Node sourceNode = edge.getEdgeSource();
Node targetNode = edge.getEdgeTarget();
/ * if (targetNode.isDataType()) {
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 {
QVTruntimeUtil.errPrintln("No assignment in " + this + " to " + slotVariableExp + "." + property);
* /
}
}
} */
private void createRealizedVariables() {
List<@NonNull Node> sortedNodes = Lists.newArrayList(partition.getPartialNodes());
Collections.sort(sortedNodes,NameUtil.NAMEABLE_COMPARATOR);
for (@NonNull Node node : sortedNodes) {
Role nodeRole = partition.getRole(node);
if ((nodeRole != null) && nodeRole.isNew() && /*newNode.isPattern() &&*/ node.isClass()) {
ExpressionCreator expressionCreator = new ExpressionCreator(this);
OCLExpression constructor = null;
if (node.isOperation()) {
if (node instanceof KeyedValueNode) {
KeyedValueNode keyedValueNode = (KeyedValueNode)node;
ClassDatum classDatum = keyedValueNode.getClassDatumValue();
assert classDatum != null;
Function function = visitor.getKeyFunction(classDatum);
VariableExp thisExp = helper.createVariableExp(QVTimperativeUtil.getContextVariable(scheduleManager.getStandardLibrary(), getTransformation()));
Map<@NonNull PropertyDatum, @NonNull VariableExp> propertyDatum2expression = new HashMap<>();
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge instanceof KeyPartEdge) {
KeyPartEdge keyPartEdge = (KeyPartEdge)edge;
PropertyDatum propertyDatum = QVTscheduleUtil.getReferredPart(keyPartEdge);
VariableExp subexpressionNode = getSubexpressionVariableExp(QVTscheduleUtil.getSourceNode(edge));
propertyDatum2expression.put(propertyDatum, subexpressionNode);
}
}
List<@NonNull OCLExpression> asArguments = new ArrayList<>();
for (@NonNull PropertyDatum propertyDatum : QVTscheduleUtil.getOwnedPropertyDatums(classDatum)) {
if (propertyDatum.isKey()) {
OCLExpression asArgument = propertyDatum2expression.get(propertyDatum);
if (asArgument == null) {
asArgument = helper.createInvalidExpression();
}
asArguments.add(asArgument);
}
}
constructor = helper.createOperationCallExp(thisExp, function, asArguments);
}
if (constructor == null) {
constructor = ((OperationCallExp)node.getOriginatingElement()).accept(expressionCreator);
}
}
ClassDatum classDatum = node.getClassDatum();
TypedModel pTypedModel = classDatum.getReferredTypedModel();
ImperativeTypedModel iTypedModel = ClassUtil.nonNullState(visitor.getQVTiTypedModel(pTypedModel));
NewStatement newStatement = helper.createNewStatement(getSafeName(node), iTypedModel, classDatum.getPrimaryClass());
newStatement.setOwnedExpression(constructor);
newStatement.setIsContained(node.isContained());
mapping.getOwnedStatements().add(newStatement);
VariableDeclaration oldVariable = node2variable.put(node, newStatement);
assert oldVariable == null;
}
}
}
private @NonNull OCLExpression createVariableExp(@NonNull Node node) {
if (node.isNullLiteral()) {
return helper.createNullLiteralExp();
}
else {
VariableDeclaration variable = getVariable(node);
return PivotUtil.createVariableExp(variable);
}
}
@Override
public @NonNull List<@NonNull Node> getGuardNodes() {
return guardNodes;
}
@Override
public @NonNull MappingParameter getGuardVariable(@NonNull Node node) {
VariableDeclaration variable = node2variable.get(node);
assert variable != null;
return (MappingParameter) variable;
}
public @NonNull QVTimperativeHelper getHelper() {
return helper;
}
public @NonNull Partition getPartition() {
return partition;
}
public @NonNull Set<@NonNull Node> getPrecedingNodes(@NonNull Node targetNode) {
Map<@NonNull Node, @NonNull Set<@NonNull Node>> node2precedingNodeClosure2 = node2precedingNodeClosure;
if (node2precedingNodeClosure2 == null) {
node2precedingNodeClosure = node2precedingNodeClosure2 = new HashMap<>();
}
Set<@NonNull Node> precedingNodes = node2precedingNodeClosure2.get(targetNode);
if (precedingNodes == null) {
precedingNodes = new HashSet<>();
node2precedingNodeClosure2.put(targetNode, precedingNodes);
precedingNodes.add(targetNode);
for (@NonNull Node sourceNode : reachabilityForest.getPredecessors(targetNode)) {
precedingNodes.addAll(getPrecedingNodes(sourceNode));
}
}
assert precedingNodes.size() > 0;
return precedingNodes;
}
public @NonNull QVTbaseLibraryHelper getQVTbaseLibraryHelper() {
return scheduleManager.getQVTbaseLibraryHelper();
}
private @NonNull VariableDeclaration getSubexpressionDeclaration(@NonNull Node node) {
VariableDeclaration variable = node2variable.get(node);
if (variable == null) {
ExpressionCreator expressionCreator = new ExpressionCreator(this);
ExpressionCreator inlineExpressionCreator = expressionCreator.getInlineExpressionCreator();
OCLExpression targetExpression = inlineExpressionCreator.getExpression(node);
assert targetExpression != null;
variable = createDeclareStatement(node, targetExpression);
}
return variable;
}
private @NonNull VariableExp getSubexpressionVariableExp(@NonNull Node node) {
return helper.createVariableExp(getSubexpressionDeclaration(node));
}
public @NonNull Transformation getTransformation() {
return visitor.getTransformation();
}
protected @NonNull VariableDeclaration getVariable(@NonNull Node node) {
return getSubexpressionDeclaration(node);
/* VariableDeclaration variable = node2variable.get(node);
if (variable == null) {
ExpressionCreator expressionCreator = new ExpressionCreator();
TypedElement typedElement = node.getTypedElements().iterator().next();
OCLExpression initExpression = typedElement.accept(expressionCreator);
variable = createDeclareStatement(node, initExpression);
}
return variable; */
}
private boolean isInfallible() {
PartitionedTransformationAnalysis partitionedTransformationAnalysis = regionAnalysis.getPartitionedTransformationAnalysis();
FallibilityAnalysis fallibilityAnalysis = partitionedTransformationAnalysis.getFallibilityAnalysis(partition);
return fallibilityAnalysis.isInfallible();
}
private boolean isTerminating() {
PartitionedTransformationAnalysis partitionedTransformationAnalysis = regionAnalysis.getPartitionedTransformationAnalysis();
FallibilityAnalysis fallibilityAnalysis = partitionedTransformationAnalysis.getFallibilityAnalysis(partition);
return fallibilityAnalysis.isTerminating();
}
/**
* 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<>(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.getEdgeTarget();
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.getEdgeTarget()) {
Property forwardProperty = QVTscheduleUtil.getReferredProperty(forwardEdge);
Property reverseProperty = QVTscheduleUtil.getReferredProperty(reverseEdge);
if (forwardProperty.getOpposite() == reverseProperty) {
if (forwardProperty.isIsImplicit()) {
forwardEdges.remove(forwardEdge);
}
else if (reverseProperty.isIsImplicit()) {
reverseEdges.remove(reverseEdge);
}
else if (sourceNode.isDependency()) {
forwardEdges.remove(forwardEdge);
}
else if (targetNode.isDependency()) {
reverseEdges.remove(reverseEdge);
}
else { // FIXME do we prefer either direction ?
reverseEdges.remove(reverseEdge);
}
}
}
}
}
}
}
}
@Override
public void synthesizeCallStatements() {
Map<@NonNull Partition, @NonNull Map<@NonNull Node, @NonNull Node>> calls = null;
for (@NonNull Partition calledPartition : connectionManager.getCallableChildren(partition)) {
if (calls == null) {
calls = new HashMap<>();
}
Map<@NonNull Node, @NonNull Node> source2target = calls.get(calledPartition);
if (source2target == null) {
source2target = new HashMap<>();
calls.put(calledPartition, source2target);
}
AbstractPartition2Mapping calledRegion2Mapping = visitor.getPartition2Mapping(calledPartition);
for (@NonNull Node calledGuardNode : calledRegion2Mapping.getGuardNodes()) {
for (@NonNull Node callingNode : connectionManager.getPassedBindingSources(calledGuardNode)) {
if (partition.getRole(callingNode) != null) {
Node oldNode = source2target.put(callingNode, calledGuardNode);
assert oldNode == null;
}
}
for (@NonNull Node callingNode : connectionManager.getUsedBindingSources(calledGuardNode)) {
if (partition.getRole(callingNode) != null) {
Node oldNode = source2target.put(callingNode, calledGuardNode);
assert oldNode == null;
}
}
}
}
if (calls != null) {
createCallStatements(calls);
}
}
/**
* Create all the statements that support the local content of this micromapping.
*/
@Override
public void synthesizeLocalStatements() {
@SuppressWarnings("unused") String name = partition.getName();
createHeadAndGuardNodeVariables(); // BLUE/CYAN guard/append nodes
createPatternMatch(); // BLUE/CYAN nodes and edges
createRealizedVariables(); // GREEN nodes
createPropertyAssignments(); // GREEN edges
createAddStatements(); // export to append nodes
// createRealizedIncludesAssignments();
createObservedProperties(); // wrap observable clauses around hazardous accesses
}
@Override
public @NonNull String toString() {
return String.valueOf(partition);
}
}