blob: 4d5678578723bf0b506febe45b03bfa2a3de51e8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2020 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.qvtm2qvts;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.NavigationCallExp;
import org.eclipse.ocl.pivot.NullLiteralExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
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.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ExpressionSynthesizer;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RuleAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RuleHeadAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.AbstractTransformationAnalysis;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtcore.Assignment;
import org.eclipse.qvtd.pivot.qvtcore.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcore.BottomVariable;
import org.eclipse.qvtd.pivot.qvtcore.CoreDomain;
import org.eclipse.qvtd.pivot.qvtcore.CoreModel;
import org.eclipse.qvtd.pivot.qvtcore.CorePattern;
import org.eclipse.qvtd.pivot.qvtcore.EnforcementOperation;
import org.eclipse.qvtd.pivot.qvtcore.GuardPattern;
import org.eclipse.qvtd.pivot.qvtcore.Mapping;
import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment;
import org.eclipse.qvtd.pivot.qvtcore.OppositePropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcore.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcore.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcore.VariableAssignment;
import org.eclipse.qvtd.pivot.qvtcore.util.QVTcoreVisitor;
import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreUtil;
import org.eclipse.qvtd.pivot.qvtschedule.RuleRegion;
import org.eclipse.qvtd.pivot.qvtschedule.Utility;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
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.utilities.DomainUsage;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
/**
* A MappingAnalysis provides the analysis a QVTc mapping.
*/
public class MappingAnalysis extends RuleAnalysis
{
public static abstract class AbstractQVTcoreExpressionSynthesizer
extends ExpressionSynthesizer
implements QVTcoreVisitor<@Nullable Node>
{
protected AbstractQVTcoreExpressionSynthesizer(@NonNull RuleAnalysis context,
@Nullable AbstractQVTcoreExpressionSynthesizer unconditionalExpressionSynthesizer,
@NonNull Utility utility) {
super(context, unconditionalExpressionSynthesizer, utility);
}
@Override
public @Nullable Node visitAssignment(@NonNull Assignment object) {
return visitElement(object);
}
@Override
public @Nullable Node visitBottomPattern(@NonNull BottomPattern object) {
return visitCorePattern(object);
}
@Override
public @Nullable Node visitBottomVariable(@NonNull BottomVariable object) {
return visitVariable(object);
}
@Override
public @Nullable Node visitCoreDomain(@NonNull CoreDomain object) {
return visitDomain(object);
}
@Override
public @Nullable Node visitCoreModel(@NonNull CoreModel object) {
return visitBaseModel(object);
}
@Override
public @Nullable Node visitCorePattern(@NonNull CorePattern object) {
return visitPattern(object);
}
@Override
public @Nullable Node visitEnforcementOperation(@NonNull EnforcementOperation object) {
return visitElement(object);
}
@Override
public @Nullable Node visitGuardPattern(@NonNull GuardPattern object) {
return visitCorePattern(object);
}
@Override
public @Nullable Node visitGuardVariable(
org.eclipse.qvtd.pivot.qvtcore.@NonNull GuardVariable object) {
return visitVariable(object);
}
@Override
public @Nullable Node visitMapping(@NonNull Mapping object) {
return visitRule(object);
}
@Override
public @Nullable Node visitNavigationAssignment(@NonNull NavigationAssignment object) {
return visitAssignment(object);
}
@Override
public @Nullable Node visitOppositePropertyAssignment(@NonNull OppositePropertyAssignment object) {
return visitNavigationAssignment(object);
}
@Override
public @Nullable Node visitPropertyAssignment(@NonNull PropertyAssignment object) {
return visitNavigationAssignment(object);
}
@Override
public @Nullable Node visitRealizedVariable(@NonNull RealizedVariable object) {
return visitVariable(object);
}
@Override
public @Nullable Node visitVariableAssignment(@NonNull VariableAssignment object) {
return visitAssignment(object);
}
}
public static class QVTcoreExpressionSynthesizer extends AbstractQVTcoreExpressionSynthesizer
{
protected QVTcoreExpressionSynthesizer(@NonNull RuleAnalysis context,
@Nullable QVTcoreExpressionSynthesizer unconditionalExpressionSynthesizer,
@NonNull Utility utility) {
super(context, unconditionalExpressionSynthesizer, utility);
}
@Override
protected @NonNull ExpressionSynthesizer createExpressionSynthesizer(@NonNull Utility utility) {
return new QVTcoreExpressionSynthesizer(context, this, utility);
}
@Override
public @NonNull Node visitNavigationAssignment(@NonNull NavigationAssignment asNavigationAssignment) {
Node slotNode = synthesize(asNavigationAssignment.getSlotExpression());
assert slotNode.isClass();
Property property = QVTcoreUtil.getTargetProperty(asNavigationAssignment);
OCLExpression value = QVTcoreUtil.getValue(asNavigationAssignment);
helper.rewriteSafeNavigations(value);
Node targetNode = synthesize(value);
NavigableEdge navigationEdge = getNavigationEdge(slotNode, property, targetNode, asNavigationAssignment);
Node valueNode = navigationEdge.getEdgeTarget();
ClassDatum valueClassDatum = QVTscheduleUtil.getClassDatum(valueNode);
Type propertyType = PivotUtil.getType(property);
if (asNavigationAssignment.isIsPartial()) {
propertyType = PivotUtil.getElementType(((CollectionType) propertyType));
}
CompleteClass targetCompleteClass = environmentFactory.getCompleteModel().getCompleteClass(propertyType);
// Type targetType =
// propertyType;//environmentFactory.getCompleteModel().getCompleteClass(propertyType);
if (!QVTscheduleUtil.conformsToClassOrBehavioralClass(valueClassDatum, targetCompleteClass)) { // Allow value to be physical or behavioral
if (!QVTscheduleUtil.conformsToClassOrBehavioralClass(valueClassDatum, targetCompleteClass)) { // Allow value to be physical or behavioral
// See Bug 577546 where this is a dodgy downcast case.
// FIXME we could synthesize a cast, but it's easier to do oclAsType() in QVTm
// if
// (!valueCompleteClass.conformsTo(targetCompleteClass.getBehavioralClass())
// &&
// !valueCompleteClass.conformsTo(targetCompleteClass.getBehavioralClass()))
// {
// No test code follows this path.
throw new IllegalStateException("Incompatible types " + valueClassDatum + ", " + targetCompleteClass + " for " + asNavigationAssignment);
}
}
return slotNode;
}
@Override
public @NonNull Node visitOppositePropertyAssignment(@NonNull OppositePropertyAssignment asNavigationAssignment) {
return visitNavigationAssignment(asNavigationAssignment);
}
@Override
public @NonNull Node visitPropertyAssignment(@NonNull PropertyAssignment asNavigationAssignment) {
return visitNavigationAssignment(asNavigationAssignment);
}
@Override
public @Nullable Node visitVariableAssignment(@NonNull VariableAssignment variableAssignment) {
return null;
}
}
/**
* Predicates that are too complex to analyze. i.e. more than a comparison
* of a bound variable wrt a property call chain on another bound variable.
*/
private final @NonNull Set<@NonNull Predicate> complexPredicates = new HashSet<>();
/**
* All the guard patterns. (domain and mapping).
*/
private final @NonNull List<@NonNull GuardPattern> guardPatterns = new ArrayList<>();
/**
* All the bottom patterns. (domain and mapping).
*/
private final @NonNull List<@NonNull BottomPattern> bottomPatterns = new ArrayList<>();
/**
* The node for each navigable VariableDeclaration.
*/
private final @NonNull List<@NonNull NavigationAssignment> navigationAssignments = new ArrayList<>();
/**
* The variable initializers, simple predicate reference expression and
* variable assignment values that define a value for each variable.
* Variable initializers are populated lazily since not all LetVariables may
* even exist for an eager population.
*/
private @NonNull Map<@NonNull VariableDeclaration, @NonNull List<@NonNull OCLExpression>> variable2expressions = new HashMap<>();
public MappingAnalysis(@NonNull AbstractTransformationAnalysis transformationAnalysis, @NonNull RuleRegion ruleRegion) {
super(transformationAnalysis, ruleRegion);
//
Mapping mapping = (Mapping) QVTscheduleUtil.getReferredRule(ruleRegion);
GuardPattern guardPattern = QVTcoreUtil.getGuardPattern(mapping);
BottomPattern bottomPattern = QVTcoreUtil.getBottomPattern(mapping);
guardPatterns.add(guardPattern);
bottomPatterns.add(bottomPattern);
for (@NonNull Assignment assignment : QVTcoreUtil.getOwnedAssignments(bottomPattern)) {
if (assignment instanceof NavigationAssignment) {
navigationAssignments.add((NavigationAssignment) assignment);
} else if (assignment instanceof VariableAssignment) {
VariableAssignment variableAssignment = (VariableAssignment) assignment;
addExpression(QVTcoreUtil.getTargetVariable(variableAssignment),
QVTcoreUtil.getValue(variableAssignment));
}
}
for (@NonNull CoreDomain coreDomain : QVTcoreUtil.getOwnedDomains(mapping)) {
guardPattern = QVTcoreUtil.getGuardPattern(coreDomain);
bottomPattern = QVTcoreUtil.getBottomPattern(coreDomain);
guardPatterns.add(guardPattern);
bottomPatterns.add(bottomPattern);
for (@NonNull Assignment assignment : QVTcoreUtil.getOwnedAssignments(bottomPattern)) {
if (assignment instanceof NavigationAssignment) {
navigationAssignments.add((NavigationAssignment) assignment);
} else if (assignment instanceof VariableAssignment) {
VariableAssignment variableAssignment = (VariableAssignment) assignment;
addExpression(QVTcoreUtil.getTargetVariable(variableAssignment), QVTcoreUtil.getValue(variableAssignment));
}
}
}
}
protected void addExpression(@NonNull VariableDeclaration variable, @NonNull OCLExpression expression) {
List<@NonNull OCLExpression> initializers = variable2expressions.get(variable);
if (initializers == null) {
initializers = new ArrayList<>();
variable2expressions.put(variable, initializers);
}
if (!initializers.contains(expression)) { // Shouldn't really happen but variable.ownedIInit is lazy
initializers.add(expression);
}
}
/**
* Create the BLUE/CYAN computations for the RHS of assignments.
*/
protected void analyzeAssignmentValues() {
AssignmentSorter assignmentSorter = new AssignmentSorter();
for (@NonNull BottomPattern bottomPattern : bottomPatterns) {
assignmentSorter.addAll(ClassUtil.nullFree(bottomPattern.getAssignment()));
}
for (@NonNull Assignment assignment : assignmentSorter.getSortedAssignments()) {
assignment.accept(rootExpressionSynthesizer.getRequiredExpressionSynthesizer(assignment.isIsRequired()));
}
}
protected void analyzeComplexPredicates() {
/**
* Identify any assignments and hidden inputs.
*/
for (Predicate predicate : complexPredicates) {
OCLExpression conditionExpression = predicate.getConditionExpression();
/*
* if (conditionExpression instanceof OperationCallExp) {
* OperationCallExp callExp = (OperationCallExp)conditionExpression;
* OperationId operationId =
* callExp.getReferredOperation().getOperationId(); if
* (ScheduleModel.isSameOperation(operationId,
* getScheduleModel().getOclAnyEqualsId())) { OCLExpression
* leftExpression = callExp.getOwnedSource(); OCLExpression
* rightExpression = callExp.getOwnedArguments().get(0); Node
* leftNode = expressionAnalyzer.analyze(leftExpression); Node
* rightNode = expressionAnalyzer.analyze(rightExpression); if
* (leftNode != rightNode) { if (leftNode.isKnown() &&
* !(leftExpression instanceof NavigationCallExp)) {
* QVTscheduleUtil.ARGUMENT.createEdge(this, leftNode, "=",
* rightNode); } else if (rightNode.isKnown() && !(rightExpression
* instanceof NavigationCallExp)) {
* QVTscheduleUtil.ARGUMENT.createEdge(this, rightNode, "=",
* leftNode); } else if (leftNode.isKnown()) {
* QVTscheduleUtil.ARGUMENT.createEdge(this, leftNode, "=",
* rightNode); } else if (rightNode.isKnown()) {
* QVTscheduleUtil.ARGUMENT.createEdge(this, rightNode, "=",
* leftNode); } else { QVTscheduleUtil.BINDING.createEdge(this,
* leftNode, null, rightNode); // FIXME
* QVTscheduleUtil.BINDING.createEdge(this, rightNode, null,
* leftNode); } } } } else {
*/
Node resultNode = conditionExpression.accept(rootExpressionSynthesizer);
if (resultNode != null) {
Node trueNode = createBooleanLiteralNode(Utility.NON_NULL_MATCHED, true);
createPredicateEdge(Utility.NON_NULL_MATCHED, resultNode, trueNode, false);
}
// FIXME ?? do includes() here explicitly
}
}
protected void analyzeContainments() {
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
if (node.isNew()) {
boolean isContained = false;
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(node)) {
if (edge.isNavigation()) {
NavigationEdge navigationEdge = (NavigationEdge) edge;
Property property = QVTscheduleUtil.getReferredProperty(navigationEdge);
Property opposite = property.getOpposite();
if ((opposite != null) && opposite.isIsComposite() && !edge.getEdgeTarget().isNullLiteral()) {
isContained = true;
break;
}
}
}
if (isContained) {
node.setContained(true);
}
}
}
}
/**
* Create a BLUE/CYAN node for each guard variable.
*/
protected void analyzeGuardVariables() {
for (@NonNull GuardPattern guardPattern : guardPatterns) {
for (@NonNull VariableDeclaration guardVariable : ClassUtil.nullFree(guardPattern.getOwnedVariables())) {
Node guardNode = region.getNode(guardVariable);
assert guardNode == null;
guardNode = createOldNode(Utility.NON_NULL_MATCHED, guardVariable);
assert guardNode == region.getNode(guardVariable);
}
}
}
/**
* Analyze the predicates to partition the guard variables into the distinct
* inputs that are not mutually navigable as a consequence of predicate
* constraints.
*
* @param bottomPatterns
*/
protected void analyzePredicates(@NonNull List<@NonNull ? extends CorePattern> corePatterns) {
//
// Populate the targetVariable2sourceVariable2paths from the simple "a.b
// = c" style predicates,
// and cache those that are too hard to analyze as complex predicates.
//
for (@NonNull CorePattern corePattern : corePatterns) {
for (@NonNull Predicate predicate : ClassUtil.nullFree(corePattern.getPredicate())) {
OCLExpression conditionExpression = predicate.getConditionExpression();
if (conditionExpression != null) {
OCLExpression boundExpression = getPredicateComparisonBoundExpression(conditionExpression);
if (boundExpression instanceof VariableExp) {
OCLExpression referenceExpression = getPredicateComparisonReferenceExpression(conditionExpression);
assert referenceExpression != null;
VariableDeclaration referredVariable = QVTcoreUtil.getReferredVariable(((VariableExp) boundExpression));
// if (referredVariable instanceof BottomVariable) {
// addExpression(referredVariable, referenceExpression);
// }
// else {
if (!analyzeSimplePredicate(referredVariable, referenceExpression)) {
complexPredicates.add(predicate);
}
// }
} else if (boundExpression instanceof NullLiteralExp) {
OCLExpression referenceExpression = getPredicateComparisonReferenceExpression(conditionExpression);
assert referenceExpression != null;
if (!analyzeSimplePredicate(null, referenceExpression)) {
complexPredicates.add(predicate);
}
} else {
complexPredicates.add(predicate);
}
}
}
}
return;
}
/**
* Create a GREEN node for each realized variable.
*/
protected void analyzeRealizedVariables() {
for (@NonNull BottomPattern bottomPattern : bottomPatterns) {
for (@NonNull RealizedVariable realizedVariable : ClassUtil.nullFree(bottomPattern.getRealizedVariable())) {
Node realizedNode = region.getNode(realizedVariable);
assert realizedNode == null;
ClassDatum classDatum = scheduleManager.getClassDatum(realizedVariable);
boolean isTrace = classDatum.getReferredTypedModel().isIsTrace();
realizedNode = createRealizedStepNode(isTrace ? Utility.TRACE : Utility.NON_NULL_MATCHED, realizedVariable);
assert realizedNode == region.getNode(realizedVariable);
}
}
}
@Override
public void analyzeMappingRegion() {
//
// Create the BLUE/CYAN guard nodes.
//
analyzeGuardVariables();
//
// Create the GREEN realized nodes.
//
analyzeRealizedVariables(); // FIXME bottom variables too
//
// Create the predicate/computation nodes and edges
//
analyzePredicates(guardPatterns);
analyzePredicates(bottomPatterns);
analyzeAssignmentValues();
analyzeComplexPredicates();
analyzeContainments();
rewriteCastEdges();
//
Iterable<@NonNull Node> headNodes = RuleHeadAnalysis.computeRuleHeadNodes(scheduleManager, region, null);
Iterables.addAll(QVTscheduleUtil.Internal.getHeadNodesList(region), headNodes);
}
//
// Install the targetVariable2sourceVariable2paths entries for a
// "boundVariable = referenceExpression" predicate,
// where the referenceExpression involves zero or more PropertyCallExps of a
// VariableExp. boundVariable may be null
// for a negative application condition.
//
// A reverse entry is also created if no PropertyCallExp is not to-one.
//
private boolean analyzeSimplePredicate(@Nullable VariableDeclaration boundVariable, @NonNull OCLExpression referenceExpression) {
boolean isValid = false;
for (@NonNull OCLExpression expression = referenceExpression; expression instanceof NavigationCallExp;) {
NavigationCallExp navigationCallExp = (NavigationCallExp) expression;
expression = ClassUtil.nonNullState(navigationCallExp.getOwnedSource());
if (expression instanceof VariableExp) {
isValid = true;
break;
}
}
if (!isValid) {
return false;
}
for (@NonNull OCLExpression expression = referenceExpression; expression instanceof NavigationCallExp;) {
NavigationCallExp navigationCallExp = (NavigationCallExp) expression;
Property referredProperty = PivotUtil.getReferredProperty(navigationCallExp);
assert referredProperty != null;
expression = ClassUtil.nonNullState(navigationCallExp.getOwnedSource());
if (expression instanceof VariableExp) {
VariableDeclaration sourceVariable = ((VariableExp) expression).getReferredVariable();
assert sourceVariable != null;
// assert guardVariables.contains(targetVariable);
// assert guardVariables.contains(sourceVariable);
Node sourceNode = getReferenceNode(sourceVariable);
Node targetNode = boundVariable != null ? getReferenceNode(boundVariable) : createNullLiteralNode(Utility.NON_NULL_MATCHED, null);
// assert sourceNode.isGuard();
// assert (boundVariable == null) || targetNode.isGuard();
assert sourceNode.isClass();
if (!referredProperty.isIsMany()) {
Edge predicateEdge = sourceNode.getOutgoingPredicateEdge(referredProperty);
if (predicateEdge == null) {
createNavigationEdge(Utility.NON_NULL_MATCHED, sourceNode, referredProperty, targetNode, false);
} else {
assert predicateEdge.getEdgeTarget() == targetNode;
}
}
}
}
return true;
}
private @Nullable Node analyzeVariable(@NonNull Variable variable, @NonNull List<@NonNull OCLExpression> expressions) {
//
// Use something hard to compute as the initializer that creates an
// initNode in the hope that other
// initializers might be easier and optimized as simple navigation
// edges.
//
OCLExpression bestInitExpression = null;
for (@NonNull OCLExpression initExpression : expressions) {
if (initExpression instanceof OperationCallExp) {
OperationCallExp operationCallExp = (OperationCallExp) initExpression;
OperationId operationId = operationCallExp.getReferredOperation().getOperationId();
if (!PivotUtil.isSameOperation(operationId,
OperationId.OCLANY_EQUALS) && !PivotUtil.isSameOperation(operationId, OperationId.OCLANY_NOT_EQUALS)) {
bestInitExpression = initExpression;
break;
}
}
}
if (bestInitExpression == null) {
bestInitExpression = (expressions.size() > 0) ? expressions.get(0) : null;
}
if (bestInitExpression == null) {
return null;
}
Node bestInitNode = bestInitExpression.accept(rootExpressionSynthesizer.getRequiredExpressionSynthesizer(variable.isIsRequired()));
assert bestInitNode != null;
/*
* if ((ownedInit instanceof OperationCallExp) &&
* initNode.isOperation()) { if
* (QVTbaseUtil.isIdentification(((OperationCallExp)ownedInit).
* getReferredOperation())) { Node stepNode =
* QVTscheduleUtil.createRealizedStepNode(mappingRegion, variable);
* QVTscheduleUtil.createEqualsEdge(initNode, stepNode); initNode =
* stepNode; } // else if (variable.getType() instanceof CollectionType)
* { // Node stepNode = QVTscheduleUtil.ATTRIBUTE.createNode(this,
* variable, (OperationCallExp)ownedInit); //
* QVTscheduleUtil.RESULT.createEdge(this, initNode, null, stepNode); //
* initNode = stepNode; // } else { // Node stepNode =
* QVTscheduleUtil.STEP.createNode(this, variable.getName(),
* (OperationCallExp)ownedInit, initNode); Node stepNode =
* QVTscheduleUtil.createLoadedStepNode(mappingRegion, variable);
* QVTscheduleUtil.createEqualsEdge(initNode, stepNode); initNode =
* stepNode; } }
*/
ClassDatum initClassDatum = QVTscheduleUtil.getClassDatum(bestInitNode);
ClassDatum variableClassDatum = scheduleManager.getClassDatum(variable);
if (!QVTscheduleUtil.conformsTo(initClassDatum, variableClassDatum)) {
Node castNode = createOldNode(Utility.getRequiredUtility(variable), variable);
rootExpressionSynthesizer.createCastEdge(bestInitNode, variableClassDatum, castNode);
bestInitNode = castNode;
}
// if (Iterables.isEmpty(bestInitNode.getTypedElements())) {
bestInitNode.setOriginatingVariable(variable);
// }
region.addVariableNode(variable, bestInitNode);
for (@NonNull OCLExpression initExpression : expressions) {
if (initExpression != bestInitExpression) {
// FIXME if the extra init is a navigation we can add a
// navigation to the bestInitNode
Node initNode = bestInitExpression.accept(rootExpressionSynthesizer);
assert initNode != null;
createEqualsEdge(initNode.getUtility(), bestInitNode, initNode);
}
}
return bestInitNode;
}
/**
* Return the boundExpression if conditionExpression is of the form <br>
* "variable = referenceExpression" => VariableExp(variable) <br>
* "referenceExpression = variable" => VariableExp(variable) <br>
* "null = referenceExpression" => NullLiteralExp(null) <br>
* "referenceExpression = null" => NullLiteralExp(null) <br>
* "constant-expression = referenceExpression" => OCLExpression(constant)
* <br>
* "referenceExpression = constant-expression" => OCLExpression(constant)
*
* <br>
* Returns null otherwise.
*/
private @Nullable OCLExpression getPredicateComparisonBoundExpression(@NonNull OCLExpression conditionExpression) {
if (conditionExpression instanceof OperationCallExp) {
OperationCallExp callExp = (OperationCallExp) conditionExpression;
OperationId operationId = callExp.getReferredOperation().getOperationId();
if (PivotUtil.isSameOperation(operationId, scheduleManager.getStandardLibraryHelper().getOclAnyEqualsId())) {
OCLExpression leftExp = callExp.getOwnedSource();
if (leftExp instanceof VariableExp) {
return leftExp;
}
OCLExpression rightExp = callExp.getOwnedArguments().get(0);
if (rightExp instanceof VariableExp) {
return rightExp;
}
IsConstantExpressionVisitor isConstantExpressionVisitor = new IsConstantExpressionVisitor(null);
if (isConstantExpressionVisitor.isConstant(leftExp)) {
return leftExp;
}
if (isConstantExpressionVisitor.isConstant(rightExp)) {
return rightExp;
}
}
}
return null;
}
/**
* Return the referenceExpression if conditionExpression is of the form
* "boundVariable = referenceExpression" or "referenceExpression =
* boundVariable". Returns null otherwise.
*/
private @Nullable OCLExpression getPredicateComparisonReferenceExpression(@NonNull OCLExpression conditionExpression) {
if (conditionExpression instanceof OperationCallExp) {
OperationCallExp callExp = (OperationCallExp) conditionExpression;
OperationId operationId = callExp.getReferredOperation().getOperationId();
if (PivotUtil.isSameOperation(operationId, scheduleManager.getStandardLibraryHelper().getOclAnyEqualsId())) {
OCLExpression leftExp = callExp.getOwnedSource();
OCLExpression rightExp = callExp.getOwnedArguments().get(0);
if (leftExp instanceof VariableExp) {
return rightExp;
} else if (rightExp instanceof VariableExp) {
return leftExp;
}
IsConstantExpressionVisitor isConstantExpressionVisitor = new IsConstantExpressionVisitor(null);
if (isConstantExpressionVisitor.isConstant(leftExp)) {
return rightExp;
}
if (isConstantExpressionVisitor.isConstant(rightExp)) {
return leftExp;
}
}
}
return null;
}
@Override
public @NonNull Node getReferenceNode(@NonNull VariableDeclaration variableDeclaration) {
Node node = region.getNode(variableDeclaration);
if (node == null) {
if (variableDeclaration instanceof Variable) {
Variable variable = (Variable) variableDeclaration;
OCLExpression ownedInit = variable.getOwnedInit();
if (ownedInit != null) {
addExpression(variable, ownedInit);
}
List<@NonNull OCLExpression> expressions = variable2expressions.get(variable);
if (expressions != null) {
node = analyzeVariable(variable, expressions);
} else if (variable.eContainer() instanceof BottomPattern) {
DomainUsage domainUsage = scheduleManager.getDomainUsage(variable);
boolean isEnforceable = scheduleManager.isOutputInRule(QVTbaseUtil.getContainingRule(variable), variable)
|| domainUsage.isMiddle();
if (isEnforceable) {
// assert variable instanceof RealizedVariable;
if (!(variable instanceof RealizedVariable)) {
CompilerUtil.addRegionError(getProblemHandler(), region,
"Enforceable variable ''{0}'' has not been realized in ''{1}''",
variable, region);
}
node = createRealizedStepNode(Utility.getRequiredUtility(variable), variable);
} else {
node = createLoadedStepNode(Utility.getRequiredUtility(variable), variable); // FIXME Predicated ??
}
}
}
}
assert node != null : "No variable2simpleNode entry for " + variableDeclaration;
return node;
/*
* if (variable instanceof RealizedVariable) { return
* QVTscheduleUtil.REALIZED_VARIABLE.createNode(this,
* (RealizedVariable)variable); } else if (variable.eContainer()
* instanceof BottomPattern) { return
* QVTscheduleUtil.UNREALIZED_VARIABLE.createNode(this, variable); }
* else { return new GuardVariableNode(this, variable); }
*/
}
/**
* Return true if the navigation from sourceNode using source2targetProperty
* corresponds to a PropertyAssigmment,
*/
@Override
public boolean isPropertyAssignment(@NonNull Node sourceNode, @NonNull Property source2targetProperty) {
if (sourceNode.isRealized()) {
for (@NonNull NavigationAssignment navigationAssignment : navigationAssignments) {
Property navigationProperty = QVTcoreUtil.getTargetProperty(navigationAssignment);
if (source2targetProperty == navigationProperty) { // ??? opposites ??? do they even exist ???
Node slotNode = rootExpressionSynthesizer.synthesize(navigationAssignment.getSlotExpression());
if (slotNode == sourceNode) {
return true;
}
}
}
}
return false;
}
}