blob: 29038ce0f0f524c7f47d45da6130474af9d40f39 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2018 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.qvtb2qvts;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.BooleanLiteralExp;
import org.eclipse.ocl.pivot.CallExp;
import org.eclipse.ocl.pivot.Class;
import org.eclipse.ocl.pivot.CollectionItem;
import org.eclipse.ocl.pivot.CollectionLiteralExp;
import org.eclipse.ocl.pivot.CollectionLiteralPart;
import org.eclipse.ocl.pivot.CollectionRange;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.EnumLiteralExp;
import org.eclipse.ocl.pivot.EnumerationLiteral;
import org.eclipse.ocl.pivot.IfExp;
import org.eclipse.ocl.pivot.IntegerLiteralExp;
import org.eclipse.ocl.pivot.IterateExp;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.LetExp;
import org.eclipse.ocl.pivot.LoopExp;
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.NullLiteralExp;
import org.eclipse.ocl.pivot.NumericLiteralExp;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.RealLiteralExp;
import org.eclipse.ocl.pivot.ShadowExp;
import org.eclipse.ocl.pivot.ShadowPart;
import org.eclipse.ocl.pivot.StringLiteralExp;
import org.eclipse.ocl.pivot.TupleLiteralExp;
import org.eclipse.ocl.pivot.TupleLiteralPart;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypeExp;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.ids.OperationId;
import org.eclipse.ocl.pivot.util.Visitable;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.util.AbstractExtendingQVTbaseVisitor;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseHelper;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtbase.utilities.StandardLibraryHelper;
import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment;
import org.eclipse.qvtd.pivot.qvtschedule.CastEdge;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.CollectionLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.EnumLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.MapLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.MappingNode;
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.OperationNode;
import org.eclipse.qvtd.pivot.qvtschedule.OperationRegion;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.RuleRegion;
import org.eclipse.qvtd.pivot.qvtschedule.ShadowNode;
import org.eclipse.qvtd.pivot.qvtschedule.TupleLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.TypeLiteralNode;
import org.eclipse.qvtd.pivot.qvtschedule.impl.RuleRegionImpl;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import org.eclipse.qvtd.runtime.utilities.QVTruntimeLibraryHelper;
public abstract class ExpressionSynthesizer extends AbstractExtendingQVTbaseVisitor<@Nullable Node, @NonNull RuleAnalysis>
{
// private static final @NonNull String @NonNull [] ifArgNames = new @NonNull String[]{QVTscheduleConstants.IF_CONDITION_NAME, QVTscheduleConstants.IF_THEN_NAME, QVTscheduleConstants.IF_ELSE_NAME};
// private static final @NonNull String @NonNull [] mapArgNames = new @NonNull String[]{"«key»", "«value»"};
// private static final @NonNull String @NonNull [] nullArgNames = new @NonNull String[]{QVTscheduleConstants.EQUALS_NAME};
// private static final @NonNull String @NonNull [] rangeArgNames = new @NonNull String[]{"«first»", "«last»"};
// private static final @NonNull String @NonNull [] srcArgNames = new @NonNull String[]{"«source»", "«arg»"};
protected final @NonNull ScheduleManager scheduleManager;
protected final @NonNull EnvironmentFactory environmentFactory;
protected final @NonNull QVTbaseHelper helper;
protected final @NonNull StandardLibraryHelper standardLibraryHelper;
protected final @NonNull QVTruntimeLibraryHelper qvtbaseLibraryHelper;
private /*@LazyNonNull*/ ExpressionSynthesizer conditionalExpressionSynthesizer = null;
private /*@LazyNonNull*/ ExpressionSynthesizer requiredExpressionSynthesizer = null;
// private /*@LazyNonNull*/ OperationDependencyAnalysis operationDependencyAnalysis;
/**
* Map from the non-trivial side of an "=" expression to the known node for a variable on the other side. This avoids the need to create a redundant
* node for the other side with an «equals» edge to tie them together.
*/
private @Nullable Map<@NonNull OCLExpression, @NonNull Node> expression2knownNode;
protected ExpressionSynthesizer(@NonNull RuleAnalysis context) {
super(context);
this.scheduleManager = context.getScheduleManager();
this.environmentFactory = scheduleManager.getEnvironmentFactory();
this.helper = new QVTbaseHelper(environmentFactory);
this.standardLibraryHelper = scheduleManager.getStandardLibraryHelper();
this.qvtbaseLibraryHelper = scheduleManager.getQVTruntimeLibraryHelper();
// this.operationDependencyAnalysis = getOperationDependencyAnalysis();
}
protected @NonNull Node createBooleanLiteralNode(boolean booleanValue, @NonNull BooleanLiteralExp booleanLiteralExp) {
return context.createBooleanLiteralNode(isUnconditional(), booleanValue, booleanLiteralExp);
}
public @NonNull CastEdge createCastEdge(@NonNull Node sourceNode, @NonNull ClassDatum classDatum, @NonNull Node castNode) {
return context.createCastEdge(sourceNode, classDatum, castNode);
}
protected @NonNull Node createCollectionLiteral(@NonNull CollectionLiteralExp collectionLiteralExp, @NonNull CollectionLiteralPart [] collectionParts, @NonNull Node @NonNull [] partNodes) {
Operation collectionOperation = qvtbaseLibraryHelper.getCollectionOperation();
assert collectionParts.length == partNodes.length;
Node reusedNode = findOperationNode(collectionOperation, partNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(collectionLiteralExp);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(collectionLiteralExp);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(collectionOperation);
}
CollectionLiteralNode collectionLiteralNode = context.createCollectionLiteralNode(isUnconditional(), nodeName, collectionLiteralExp, partNodes);
for (int i = 0; i < collectionParts.length; i++) {
context.createCollectionPartEdge(partNodes[i], collectionParts[i], collectionLiteralNode);
}
return collectionLiteralNode;
}
protected @NonNull Node createCollectionRange(@NonNull CollectionRange collectionRange, @NonNull Node firstNode, @NonNull Node lastNode) {
Operation rangeOperation = qvtbaseLibraryHelper.getRangeOperation();
@NonNull Node[] sourceAndArgumentNodes = new @NonNull Node[] { firstNode, lastNode };
Node reusedNode = findOperationNode(rangeOperation, sourceAndArgumentNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(collectionRange);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(collectionRange);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(rangeOperation);
}
Node operationNode = context.createCollectionRangeNode(isUnconditional(), nodeName, collectionRange, sourceAndArgumentNodes);
Parameter firstParameter = qvtbaseLibraryHelper.getRangeFirstParameter();
Parameter lastParameter = qvtbaseLibraryHelper.getRangeLastParameter();
createOperationParameterEdge(firstNode, firstParameter, -1, operationNode);
createOperationParameterEdge(lastNode, lastParameter, -1, operationNode);
return operationNode;
}
protected abstract @NonNull ExpressionSynthesizer createConditionalExpressionSynthesizer();
protected @NonNull Node createDataTypeNode(@NonNull String name, @NonNull Node sourceNode, @NonNull NavigationCallExp navigationCallExp) {
return context.createDataTypeNode(name, sourceNode, navigationCallExp);
}
protected @NonNull Edge createDependencyEdge(@NonNull Node sourceNode, @NonNull String name, @NonNull Node targetNode) {
return context.createDependencyEdge(sourceNode, name, targetNode);
}
protected @NonNull Node createDependencyNode(@NonNull String name, @NonNull ClassDatum classDatum) {
return context.createDependencyNode(name, classDatum);
}
protected @NonNull EnumLiteralNode createEnumLiteralNode(@NonNull EnumerationLiteral enumValue, @NonNull EnumLiteralExp enumLiteralExp) {
return context.createEnumLiteralNode(isUnconditional(), enumValue, enumLiteralExp);
}
protected @NonNull Node createErrorNode(@NonNull String name, @NonNull ClassDatum classDatum) {
return context.createErrorNode(name, classDatum);
}
protected @NonNull Edge createEqualsEdge(@NonNull Node sourceNode, @NonNull Node targetNode) {
return context.createEqualsEdge(sourceNode, targetNode);
}
protected @NonNull Node createIf(@NonNull IfExp ifExp, @NonNull Node selfNode, @NonNull Node thenNode, @NonNull Node elseNode) {
Operation ifOperation = qvtbaseLibraryHelper.getIfOperation();
@NonNull Node [] sourceAndArgumentNodes = new @NonNull Node[] { selfNode, thenNode, elseNode };
Node reusedNode = findOperationNode(ifOperation, sourceAndArgumentNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(ifExp);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(ifExp);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(ifOperation);
}
// Node operationNode = nestedAnalyzer.createOperationNode(nodeName, typedElement, sourceAndArgumentNodes);
Node operationNode = context.createIfNode(isUnconditional(), nodeName, ifExp, sourceAndArgumentNodes);
// org.eclipse.ocl.pivot.Class selfType = standardLibraryHelper.getStandardLibrary().getBooleanType();
Parameter conditionParameter = qvtbaseLibraryHelper.getIfConditionParameter();
Parameter thenParameter = qvtbaseLibraryHelper.getIfThenParameter();
Parameter elseParameter = qvtbaseLibraryHelper.getIfElseParameter();
// createOperationSelfEdge(selfNode, selfType, operationNode);
createOperationParameterEdge(selfNode, conditionParameter, -1, operationNode);
createOperationParameterEdge(thenNode, thenParameter, -1, operationNode);
createOperationParameterEdge(elseNode, elseParameter, -1, operationNode);
return operationNode;
}
protected @NonNull Edge createIteratedEdge(@NonNull Node sourceNode, @NonNull Node targetNode) {
return context.createIteratedEdge(sourceNode, targetNode);
}
protected @NonNull Node createIteratorNode(@NonNull Variable iterator, @NonNull Node sourceNode) {
return context.createIteratorNode(iterator, sourceNode);
}
protected @NonNull Node createLetNode(@NonNull Variable letVariable, @NonNull Node inNode) {
return context.createLetVariableNode(letVariable, inNode);
}
protected @NonNull Node createMapLiteral(@NonNull MapLiteralExp mapLiteralExp, @NonNull MapLiteralPart [] mapParts, @NonNull Node @NonNull [] partNodes) {
assert mapParts.length == partNodes.length;
Operation mapOperation = qvtbaseLibraryHelper.getMapOperation();
Node reusedNode = findOperationNode(mapOperation, partNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(mapLiteralExp);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(mapLiteralExp);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(mapOperation);
}
MapLiteralNode mapLiteralNode = context.createMapLiteralNode(isUnconditional(), nodeName, mapLiteralExp, partNodes);
for (int i = 0; i < mapParts.length; i++) {
context.createMapPartEdge(partNodes[i], mapParts[i], mapLiteralNode);
}
return mapLiteralNode;
}
protected @NonNull Node createNavigableDataTypeNode(@NonNull Node targetNode, @NonNull NavigationAssignment navigationAssignment) {
return context.createDataTypeNode(targetNode, navigationAssignment);
}
protected @NonNull Node createMapPart(@NonNull MapLiteralPart mapLiteralPart, @NonNull Node keyNode, @NonNull Node valueNode) {
TypedElement typedElement = QVTbaseUtil.getOwnedValue(mapLiteralPart); // FIXME use real object
Operation partOperation = qvtbaseLibraryHelper.getMapPartOperation();
@NonNull Node[] subPartNodes = new @NonNull Node[] { keyNode, valueNode };
Node reusedNode = findOperationNode(partOperation, subPartNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(typedElement);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(typedElement);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(partOperation);
}
Node operationNode = context.createMapPartNode(isUnconditional(), nodeName, mapLiteralPart, subPartNodes);
Parameter keyParameter = qvtbaseLibraryHelper.getMapPartKeyParameter();
Parameter valueParameter = qvtbaseLibraryHelper.getMapPartValueParameter();
createOperationParameterEdge(keyNode, keyParameter, -1, operationNode);
createOperationParameterEdge(valueNode, valueParameter, -1, operationNode);
return operationNode;
}
protected @NonNull Node createNavigableDataTypeNode(@NonNull Node sourceNode, @NonNull Property source2targetProperty) {
assert sourceNode.isMatched();
return context.createDataTypeNode(sourceNode, source2targetProperty);
}
protected @NonNull NavigableEdge createNavigableNavigationEdge(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode) {
return context.createNavigationEdge(sourceNode, source2targetProperty, targetNode, false);
}
protected @NonNull NavigableEdge createNavigationEdge(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, boolean isPartial) {
return context.createNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial);
}
protected @NonNull NavigableEdge createNavigationOrRealizedEdge(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(source2targetProperty);
assert navigationEdge == null;
boolean isPartial = navigationAssignment != null ? navigationAssignment.isIsPartial() : scheduleManager.computeIsPartial(targetNode, source2targetProperty);
if ((navigationAssignment != null) || context.isPropertyAssignment(sourceNode, source2targetProperty)) {
navigationEdge = createRealizedNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial);
}
else {
navigationEdge = createNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial);
}
return navigationEdge;
}
protected @NonNull Node createNullLiteralNode() {
return context.createNullLiteralNode(isUnconditional(), null);
}
protected @NonNull Node createNullLiteralNode(@NonNull NullLiteralExp nullLiteralExp) {
return context.createNullLiteralNode(isUnconditional(), nullLiteralExp);
}
protected @NonNull Node createNumericLiteralNode(@NonNull Number numberValue, @NonNull NumericLiteralExp numericLiteralExp) {
return context.createNumericLiteralNode(isUnconditional(), numberValue, numericLiteralExp);
}
protected @NonNull Node createOperationCallNode(@NonNull CallExp callExp, @NonNull Operation operation, @NonNull Node @NonNull [] sourceAndArgumentNodes) {
Node reusedNode = findOperationNode(operation, sourceAndArgumentNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(callExp);
return reusedNode;
}
String nameHint = CompilerUtil.recoverVariableName(callExp);
Node operationNode = context.createOperationCallNode(isUnconditional(), nameHint, operation, callExp, sourceAndArgumentNodes);
return operationNode;
}
protected @NonNull Node createOperationCallNode2(@NonNull String nameHint, @NonNull Role nodeRole, @NonNull Operation operation, @NonNull ClassDatum classDatum, @NonNull Node @NonNull ... sourceAndArgumentNodes) {
Node operationNode = context.createOperationCallNode2(nodeRole, isUnconditional(), nameHint, operation, classDatum, sourceAndArgumentNodes);
return operationNode;
}
protected @NonNull Edge createOperationParameterEdge(@NonNull Node sourceNode, @NonNull Parameter parameter, int parameterIndex, @NonNull Node targetNode) {
return context.createOperationParameterEdge(sourceNode, parameter, parameterIndex, targetNode);
}
protected @NonNull Edge createOperationSelfEdge(@NonNull Node sourceNode, @NonNull Type type, @NonNull Node targetNode) {
return context.createOperationSelfEdge(sourceNode, type, targetNode);
}
protected @NonNull Edge createPredicateEdge(@NonNull Node sourceNode, @Nullable String name, @NonNull Node targetNode) {
return context.createPredicateEdge(sourceNode, name, targetNode);
}
protected @NonNull Node createPredicatedClassNode(@NonNull Node parentNode, @NonNull NavigationAssignment navigationAssignment) {
return context.createDependencyClassNode(parentNode, navigationAssignment);
}
protected @NonNull Node createRealizedDataTypeNode(@NonNull Node sourceNode, @NonNull Property source2targetProperty) {
return context.createRealizedDataTypeNode(sourceNode, source2targetProperty);
}
protected @NonNull NavigableEdge createRealizedNavigationEdge(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, boolean isPartial) {
return context.createRealizedNavigationEdge(sourceNode, source2targetProperty, targetNode, isPartial);
}
protected abstract @NonNull ExpressionSynthesizer createRequiredExpressionSynthesizer();
protected @NonNull Node createShadow(@NonNull ShadowExp shadowExp, @NonNull ShadowPart [] shadowParts, @NonNull Node @NonNull [] partNodes) {
assert shadowParts.length == partNodes.length;
Operation shadowOperation = qvtbaseLibraryHelper.getShadowOperation();
Node reusedNode = findOperationNode(shadowOperation, partNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(shadowExp);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(shadowExp);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(shadowOperation);
}
ShadowNode shadowLiteralNode = context.createShadowNode(isUnconditional(), nodeName, shadowExp, partNodes);
for (int i = 0; i < shadowParts.length; i++) {
context.createShadowPartEdge(partNodes[i], shadowParts[i], shadowLiteralNode);
}
return shadowLiteralNode;
}
protected @NonNull Node createStepNode(@NonNull String name, @NonNull CallExp callExp, @NonNull Node sourceNode) {
return context.createStepNode(name, callExp, sourceNode, sourceNode.isMatched() && QVTscheduleUtil.isMatched(callExp));
}
protected @NonNull Node createStringLiteralNode(@NonNull String stringValue, @NonNull StringLiteralExp stringLiteralExp) {
return context.createStringLiteralNode(isUnconditional(), stringValue, stringLiteralExp);
}
protected @NonNull Node createTupleLiteral(@NonNull TupleLiteralExp tupleLiteralExp, @NonNull TupleLiteralPart [] tupleParts, @NonNull Node @NonNull [] partNodes) {
assert tupleParts.length == partNodes.length;
Operation tupleOperation = qvtbaseLibraryHelper.getTupleOperation();
Node reusedNode = findOperationNode(tupleOperation, partNodes);
if (reusedNode != null) {
// reusedNode.addTypedElement(tupleLiteralExp);
return reusedNode;
}
String nodeName = CompilerUtil.recoverVariableName(tupleLiteralExp);
if (nodeName == null) {
nodeName = QVTbaseUtil.getName(tupleOperation);
}
TupleLiteralNode tupleLiteralNode = context.createTupleLiteralNode(isUnconditional(), nodeName, tupleLiteralExp, partNodes);
for (int i = 0; i < tupleParts.length; i++) {
context.createTuplePartEdge(partNodes[i], tupleParts[i], tupleLiteralNode);
}
return tupleLiteralNode;
}
protected @NonNull TypeLiteralNode createTypeLiteralNode(@NonNull Type typeValue, @NonNull TypeExp typeExp) {
return context.createTypeLiteralNode(isUnconditional(), typeValue, typeExp);
}
protected @NonNull Node doLoopExp(@NonNull LoopExp loopExp, @NonNull Node sourceNode) {
List<@NonNull Variable> ownedIterators = ClassUtil.nullFree(loopExp.getOwnedIterators());
@NonNull Node[] argNodes = new @NonNull Node[1+ownedIterators.size()+(loopExp instanceof IterateExp ? 1 : 0)];
int i = 1;
for (@NonNull Variable iterator : ownedIterators) {
Node iteratorNode = createIteratorNode(iterator, sourceNode);
@SuppressWarnings("unused")
Type iteratorType = QVTbaseUtil.getType(iterator);
// Property iterateProperty = context.getScheduleModel().getIterateProperty(iteratorType);
createIteratedEdge(sourceNode, iteratorNode);
argNodes[i++] = iteratorNode;
}
if (loopExp instanceof IterateExp) {
Variable accumulator = QVTbaseUtil.getOwnedResult((IterateExp)loopExp);
Node iteratorNode = createIteratorNode(accumulator, sourceNode);
@SuppressWarnings("unused")
Type iteratorType = QVTbaseUtil.getType(accumulator);
// Property iterateProperty = context.getScheduleModel().getIterateProperty(iteratorType);
createIteratedEdge(sourceNode, iteratorNode);
argNodes[i++] = iteratorNode;
}
Node bodyNode = getConditionalExpressionSynthesizer().synthesize(loopExp.getOwnedBody());
argNodes[0] = bodyNode;
Iteration referredIteration = QVTbaseUtil.getReferredIteration(loopExp);
// String iterationName = "«" + referredIteration.getName() + "»";
Node accumulateNode = createOperationCallNode(loopExp, referredIteration, argNodes);
createOperationParameterEdge(sourceNode, qvtbaseLibraryHelper.getLoopSourceParameter(), -1, accumulateNode);
createOperationParameterEdge(bodyNode, qvtbaseLibraryHelper.getLoopBodyParameter(), -1, accumulateNode);
for (int j = 1 ; j <= ownedIterators.size(); j++) {
@NonNull Node iteratorNode = argNodes[j];
// createExpressionEdge(iteratorNode, "«" + iterator.getName() + "»", accumulateNode);
// createArgumentEdge(iteratorNode, iterator, -1 accumulateNode);
createOperationParameterEdge(iteratorNode, qvtbaseLibraryHelper.getLoopIteratorsParameter(), j-1, accumulateNode);
}
return accumulateNode;
}
protected @NonNull Node doNavigationCallExp(@NonNull NavigationCallExp navigationCallExp, @NonNull Node sourceNode) {
Property referredProperty = QVTbaseUtil.getReferredProperty(navigationCallExp);
if (sourceNode.isClass()) {
if (!referredProperty.isIsMany()) {
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(referredProperty);
if (navigationEdge != null) {
return navigationEdge.getEdgeTarget();
}
}
String name = CompilerUtil.recoverVariableName(navigationCallExp);
if (name == null) {
name = QVTbaseUtil.getName(referredProperty);
}
Type type = QVTbaseUtil.getType(referredProperty);
Node targetNode = expression2knownNode != null ? expression2knownNode.get(navigationCallExp) : null;
if (targetNode == null) {
if (type instanceof DataType) {
targetNode = sourceNode.getNavigableTarget(referredProperty);
if (targetNode == null) {
targetNode = createDataTypeNode(name, sourceNode, navigationCallExp);
}
}
else {
targetNode = createStepNode(name, navigationCallExp, sourceNode);
}
}
getNavigationEdge(sourceNode, referredProperty, targetNode, null);
return targetNode;
}
OCLExpression ownedSource = QVTbaseUtil.getOwnedSource(navigationCallExp);
return context.getUnknownNode(ownedSource);
}
protected @Nullable Node doOperationCallExp(@NonNull OperationCallExp operationCallExp, @Nullable Node sourceNode) {
boolean isMatched = isRequired() || QVTscheduleUtil.isMatched(operationCallExp);
Operation referredOperation = QVTbaseUtil.getReferredOperation(operationCallExp);
String operationName = ClassUtil.nonNullState(referredOperation.getName());
OCLExpression ownedSource = operationCallExp.getOwnedSource();
if (sourceNode == null) {
List<OCLExpression> ownedArguments = operationCallExp.getOwnedArguments();
int iSize = ownedArguments.size();
@NonNull Node[] argNodes = new @NonNull Node[iSize];
for (int i = 0; i < iSize; i++) {
argNodes[i] = synthesize(ownedArguments.get(i));
}
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
Node operationNode = nestedAnalyzer.createOperationCallNode(operationCallExp, referredOperation, argNodes);
if (isRequired()) {
operationNode.setRequired();
}
for (int i = 0; i < iSize; i++) {
Parameter parameter = QVTbaseUtil.getOwnedParameter(referredOperation, i);
nestedAnalyzer.createOperationParameterEdge(argNodes[i], parameter, -1, operationNode);
}
return operationNode;
}
assert ownedSource != null;
OperationId operationId = referredOperation.getOperationId();
//
// "=" is best handled as a single multi-constrained node
//
if ((operationCallExp.eContainer() instanceof Predicate)
&& !(ownedSource.getType() instanceof DataType)
&& QVTbaseUtil.isSameOperation(operationId, standardLibraryHelper.getOclAnyEqualsId())) {
return synthesizeOperationCallExp_equals(operationCallExp);
}
// FIXME "=" can identify that LHS and RHS can be coalesced
// FIXME "includes" may also indicate a coalesce
if (operationId == standardLibraryHelper.getOclAnyOclAsTypeId()) {
return synthesizeOperationCallExp_oclAsType(sourceNode, operationCallExp);
}
else if (QVTbaseUtil.isSameOperation(operationId, standardLibraryHelper.getOclElementOclContainerId())) {
return synthesizeOperationCallExp_oclContainer(sourceNode, operationCallExp);
}
// else if (QVTbaseUtil.isSameOperation(operationId, standardLibraryHelper.getOclAnyOclIsKindOfId())) {
// return synthesizeOperationCallExp_oclIsKindOf(sourceNode, operationCallExp);
// }
else if ((operationCallExp.eContainer() instanceof Predicate)
&& (sourceNode.getClassDatum().isCollectionType())
&& "includes".equals(operationName)) {
return synthesizeOperationCallExp_includes(sourceNode, operationCallExp);
}
else {
List<OCLExpression> ownedArguments = operationCallExp.getOwnedArguments();
int iSize = ownedArguments.size();
@NonNull Node[] argNodes = new @NonNull Node[iSize+1];
@NonNull String [] argNames = new @NonNull String[iSize+1];
argNodes[0] = sourceNode;
argNames[0] = "«self»";
for (int i = 0; i < iSize; i++) {
argNodes[i+1] = synthesize(ownedArguments.get(i));
argNames[i+1] = "«" + referredOperation.getOwnedParameters().get(i).getName() + "»";
}
Node operationNode = findOperationNode(referredOperation, argNodes);
if (operationNode == null) {
operationNode = createOperationCallNode(operationCallExp, referredOperation, argNodes);
for (int i = 0; i <= iSize; i++) {
// createExpressionEdge(argNodes[i], argNames[i], operationNode);
if (i == 0) {
createOperationSelfEdge(argNodes[i], QVTbaseUtil.getType(ownedSource), operationNode);
}
else {
createOperationParameterEdge(argNodes[i], QVTbaseUtil.getOwnedParameter(referredOperation, i-1), -1, operationNode);
}
}
if (referredOperation.getBodyExpression() != null) {
// QVTm2QVTs qvtm2qvts = (QVTm2QVTs) scheduleManager; // FIXME cast
OperationRegion operationRegion = scheduleManager.analyzeOperation(operationCallExp);
Iterable<@NonNull Node> referenceNodes = QVTscheduleUtil.getDependencyNodes(operationRegion);
for (@NonNull Node referenceNode : referenceNodes) {
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(referenceNode);
Node dependencyHead = context.getDependencyHead(classDatum);
if (dependencyHead == null) {
dependencyHead = context.createDependencyHead(classDatum);
createDependencyEdge(dependencyHead, QVTscheduleUtil.getName(dependencyHead), operationNode);
}
instantiate(dependencyHead, referenceNode);
}
}
}
else {
operationNode.addOriginatingElement(operationCallExp);
}
Type returnType = operationCallExp.getType();
if (returnType instanceof DataType) {
return operationNode;
}
else {
return operationNode;
}
}
}
protected @NonNull Node doSafeNavigation(@NonNull CallExp callExp, @NonNull Node sourceNode, @NonNull Node navigationNode) {
assert callExp.isIsSafe();
Type unsafeType = callExp.getType();
assert !(unsafeType instanceof MapType);
if (unsafeType instanceof CollectionType) {
Operation excludingOperation = standardLibraryHelper.getCollectionExcludingOperation();
Node nullNode = createNullLiteralNode();
Node excludingNode = createOperationCallNode2("safe"+navigationNode.getName(), QVTscheduleUtil.getNodeRole(navigationNode), excludingOperation, QVTscheduleUtil.getClassDatum(navigationNode), navigationNode, nullNode);
return excludingNode;
}
else {
Operation equalsOperation = standardLibraryHelper.getOclAnyEqualsOperation();
Node nullNode1 = createNullLiteralNode();
Node isNonNullNode = createOperationCallNode2("equals"/*"isSafe"+navigationNode.getName()*/, QVTscheduleUtil.getNodeRole(navigationNode), equalsOperation, scheduleManager.getBooleanClassDatum(), sourceNode, nullNode1);
createOperationSelfEdge(sourceNode, QVTbaseUtil.getType(QVTbaseUtil.getOwnedSource(callExp)), isNonNullNode);
createOperationParameterEdge(nullNode1, QVTbaseUtil.getOwnedParameter(equalsOperation, 0), -1, isNonNullNode);
Node nullNode2 = createNullLiteralNode();
Operation ifOperation = qvtbaseLibraryHelper.getIfOperation();
@NonNull Node [] sourceAndArgumentNodes = new @NonNull Node[] { isNonNullNode, navigationNode, nullNode2 };
String nodeName = QVTbaseUtil.getName(ifOperation);
Node ifNode = context.createIfNode2(isUnconditional(), nodeName, QVTscheduleUtil.getClassDatum(navigationNode), sourceAndArgumentNodes);
Parameter conditionParameter = qvtbaseLibraryHelper.getIfConditionParameter();
Parameter thenParameter = qvtbaseLibraryHelper.getIfThenParameter();
Parameter elseParameter = qvtbaseLibraryHelper.getIfElseParameter();
createOperationParameterEdge(isNonNullNode, conditionParameter, -1, ifNode);
createOperationParameterEdge(nullNode2, thenParameter, -1, ifNode);
createOperationParameterEdge(navigationNode, elseParameter, -1, ifNode);
return ifNode;
}
}
// FIXME switch to OPeration argument
protected @Nullable Node findOperationNode(@NonNull Operation operation, @NonNull Node @NonNull ... sourceAndArgumentNodes) {
String name = QVTbaseUtil.getName(operation);
if (sourceAndArgumentNodes.length > 0) {
for (@NonNull Edge searchEdge : QVTscheduleUtil.getOutgoingEdges(sourceAndArgumentNodes[0])) {
if (searchEdge.isComputation()) {
Node reusedNode = searchEdge.getEdgeTarget();
if (reusedNode.isOperation()) {
@SuppressWarnings("unused") OperationNode operationNode = (OperationNode)reusedNode;
boolean equals1 = name.equals(reusedNode.getName());
// boolean equals2 = operation == operationNode.getReferredOperation();
// assert equals1 == equals2;
if (equals1) {
int iSize = 0;
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(reusedNode)) {
if (edge.isExpression()) {
iSize++;
}
}
if (iSize == sourceAndArgumentNodes.length) {
int i = 0;
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(reusedNode)) {
if (edge.isExpression()) {
Node reusedArgumentNode = edge.getEdgeSource();
if (reusedArgumentNode != sourceAndArgumentNodes[i]) {
break;
}
i++;
}
}
if (i == iSize) {
return reusedNode;
}
}
}
}
}
}
}
return null;
}
private @NonNull ExpressionSynthesizer getConditionalExpressionSynthesizer() {
ExpressionSynthesizer conditionalExpressionSynthesizer2 = conditionalExpressionSynthesizer;
if (conditionalExpressionSynthesizer2 == null) {
conditionalExpressionSynthesizer = conditionalExpressionSynthesizer2 = createConditionalExpressionSynthesizer();
}
return conditionalExpressionSynthesizer2;
}
/* protected @NonNull OperationDependencyAnalysis getOperationDependencyAnalysis() {
OperationDependencyAnalysis operationDependencyAnalysis2 = operationDependencyAnalysis;
if (operationDependencyAnalysis2 == null) {
operationDependencyAnalysis = operationDependencyAnalysis2 = new OperationDependencyAnalysis(environmentFactory, scheduler.getDomainAnalysis());
}
return operationDependencyAnalysis2;
} */
/**
* Return the navigation edge suitable for navigating from sourceNode to targetNode via source2targetProperty,
* re-using an already created edge if available, otherwise creating the edge.
*/
protected @NonNull NavigableEdge getNavigationEdge(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
if (targetNode.isNullLiteral()) {
return getNavigationEdgeToNull(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
else if (targetNode.isClass() && !targetNode.isOperation()) { // FIXME rationalize isXXX tests
return getNavigationEdgeToClass(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
else if (targetNode.isDataType()) {
return getNavigationEdgeToDataType(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
else {
return getNavigationEdgeToExpression(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
}
protected @NonNull NavigableEdge getNavigationEdgeToDataType(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
assert targetNode.isDataType();
Type type = source2targetProperty.getType();
assert type instanceof DataType;
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(source2targetProperty);
if (navigationEdge == null) {
if (!targetNode.isOperation()) {
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
else {
ClassDatum propertyClassDatum = scheduleManager.getClassDatum(source2targetProperty);
ClassDatum valueClassDatum = targetNode.getClassDatum();
if (valueClassDatum == propertyClassDatum) {
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
else {
if (navigationAssignment == null) {
Node stepNode = createNavigableDataTypeNode(sourceNode, source2targetProperty);
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, stepNode, navigationAssignment);
context.createEqualsEdge(targetNode, stepNode);
}
else {
// Node stepNode = createNavigableDataTypeNode(targetNode, navigationAssignment);
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
// QVTscheduleUtil.createEqualsEdge(targetNode, stepNode);
}
}
}
}
else {
// if (!navigationEdge.isRealized() || targetNode.isRealized()) {
if (targetNode != navigationEdge.getEdgeTarget()) {
context.createEqualsEdge(targetNode, navigationEdge.getEdgeTarget());
}
}
return navigationEdge;
}
protected @NonNull NavigableEdge getNavigationEdgeToClass(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
assert targetNode.isClass();
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(source2targetProperty);
if (navigationEdge != null) {
Node target = navigationEdge.getEdgeTarget();
if (target != targetNode) {
context.createEqualsEdge(targetNode, target);
}
}
else {
// navigationEdge = createRealizedEdge(sourceNode, source2targetProperty, targetNode);
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
// Property target2sourceProperty = source2targetProperty.getOpposite(); // FIXME move to createEdge
// if (targetNode.isClassNode() && (target2sourceProperty != null) && !target2sourceProperty.isIsMany()) {
// createRealizedEdge(targetNode, target2sourceProperty, sourceNode);
// createNavigationOrRealizedEdge(targetNode, target2sourceProperty, sourceNode, isAssignment);
// }
}
return navigationEdge;
}
protected @NonNull NavigableEdge getNavigationEdgeToExpression(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
assert targetNode.isExpression();
if (navigationAssignment != null) {
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(source2targetProperty);
assert navigationEdge == null;
// Node valueNode = navigationEdge.getTarget();
// assert valueNode.isRealized();
// Type type = source2targetProperty.getType();
/* if (type instanceof DataType) {
Node attributeNode = createRealizedDataTypeNode(sourceNode, source2targetProperty);
createExpressionEdge(targetNode, EQUALS_NAME, attributeNode);
targetNode = attributeNode;
}
else {
Node stepNode = createPredicatedClassNode(sourceNode, navigationAssignment);
createExpressionEdge(targetNode, EQUALS_NAME, stepNode);
targetNode = stepNode;
} */
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
return navigationEdge;
}
else {
NavigableEdge navigationEdge = sourceNode.getOutgoingNavigableEdge(source2targetProperty);
if (navigationEdge != null) {
Node valueNode = navigationEdge.getEdgeTarget();
assert valueNode.isRealized();
Type type = source2targetProperty.getType();
Edge equalsEdge = context.createEqualsEdge(targetNode, valueNode);
if (type instanceof DataType) {
assert equalsEdge.isRealized(); // ?? obsolete legacy check that never seems to be used
}
return navigationEdge;
}
else {
navigationEdge = createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
return navigationEdge;
}
}
}
protected @NonNull NavigableEdge getNavigationEdgeToNull(@NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode, @Nullable NavigationAssignment navigationAssignment) {
assert targetNode.isNullLiteral();
return createNavigationOrRealizedEdge(sourceNode, source2targetProperty, targetNode, navigationAssignment);
}
public @NonNull ExpressionSynthesizer getRequiredExpressionSynthesizer() {
ExpressionSynthesizer requiredExpressionSynthesizer2 = requiredExpressionSynthesizer;
if (requiredExpressionSynthesizer2 == null) {
requiredExpressionSynthesizer = requiredExpressionSynthesizer2 = createRequiredExpressionSynthesizer();
}
return requiredExpressionSynthesizer2;
}
private void instantiate(@NonNull Node instantiatedNode, @NonNull Node referenceNode) {
for (@NonNull Edge referenceEdge : QVTscheduleUtil.getOutgoingEdges(referenceNode)) {
if (referenceEdge instanceof NavigationEdge) {
NavigationEdge navigationEdge = (NavigationEdge)referenceEdge;
if (!navigationEdge.isSecondary()) {
Node referenceTargetNode = navigationEdge.getEdgeTarget();
String name = QVTscheduleUtil.getName(referenceTargetNode);
ClassDatum classDatum = QVTscheduleUtil.getClassDatum(referenceTargetNode);
Node instantiatedTargetNode = createDependencyNode(name, classDatum);
createNavigationEdge(instantiatedNode, QVTscheduleUtil.getReferredProperty(navigationEdge), instantiatedTargetNode, false);
instantiate(instantiatedTargetNode, referenceTargetNode);
}
}
else {
// SharedEdge
}
}
}
protected boolean isRequired() {
return false;
}
protected boolean isUnconditional() {
return true;
}
/**
* Rewrite a CastEdge and its target node as an oclAsType call. THe castEdge and its target node are destroyed by the replacement.
*
* REturns the operation node,
*/
public @NonNull Node rewriteCastEdgeAsOclAsType(@NonNull CastEdge castEdge) {
Node sourceNode = QVTscheduleUtil.getSourceNode(castEdge);
Node targetNode = QVTscheduleUtil.getTargetNode(castEdge);
OperationCallExp operationCallExp = (OperationCallExp) targetNode.getOriginatingElement();
Operation referredOperation = PivotUtil.getReferredOperation(operationCallExp);
OCLExpression ownedSource = PivotUtil.getOwnedSource(operationCallExp);
Type sourceType = PivotUtil.getType(ownedSource);
TypeExp typeArgument = (TypeExp) PivotUtil.getOwnedArgument(operationCallExp, 0);
//
// Create oclAsType operation node, type node and argument edges.
//
Node typeNode = createTypeLiteralNode(PivotUtil.getReferredType(typeArgument), typeArgument);
ExpressionSynthesizer nestedAnalyzer = getConditionalExpressionSynthesizer();
Node operationNode = nestedAnalyzer.createOperationCallNode(operationCallExp, referredOperation, new @NonNull Node[] {sourceNode, typeNode});
if (isRequired()) {
operationNode.setRequired();
}
nestedAnalyzer.createOperationSelfEdge(sourceNode, sourceType, operationNode);
Parameter parameter = QVTbaseUtil.getOwnedParameter(referredOperation, 0);
nestedAnalyzer.createOperationParameterEdge(typeNode, parameter, -1, operationNode);
//
// Install operationNode as a replacement for targetNode.
//
CompilerUtil.migrateCastEdgeTargetContents(castEdge, operationNode);
return operationNode;
}
public @NonNull Node synthesize(/*@NonNull*/ Visitable element) {
Node accept = element.accept(this);
assert accept != null;
return accept;
}
/**
* Generate the node(s) for xxxx = yyyy where xxxx and yyy are non-trivial expressions
*
* For the terminal navigation x = yyyy.y, xxxx.x = yyyy, xxxx.x = yyyy.y a node can be shared.
*
* For terminal operfations xxxx = yyyy.y() etc it cannot (yet).
*/
private @Nullable Node synthesizeOperationCallExp_equals(@NonNull OperationCallExp operationCallExp) {
OCLExpression asSource = QVTbaseUtil.getOwnedSource(operationCallExp);
OCLExpression asTarget = QVTbaseUtil.getOwnedArgument(operationCallExp, 0);
Node sourceNode;
Node targetNode;
if (asSource instanceof VariableExp) {
VariableDeclaration referredVariable = QVTbaseUtil.getReferredVariable((VariableExp)asSource);
RuleRegion ruleRegion = context.getRegion();
sourceNode = ruleRegion.getNode(referredVariable);
if (sourceNode != null) {
Map<@NonNull OCLExpression, @NonNull Node> expression2knownNode2 = expression2knownNode;
if (expression2knownNode2 == null) {
expression2knownNode = expression2knownNode2 = new HashMap<>();
}
expression2knownNode2.put(asTarget, sourceNode);
}
targetNode = synthesize(asTarget);
if (targetNode == sourceNode) {
return null;
}
else {
// scheduleManager.addRegionError(ruleRegion, "Failed to unify simple equality predicate " + operationCallExp);
sourceNode = synthesize(asSource);
}
}
else if (asTarget instanceof VariableExp) {
VariableDeclaration referredVariable = QVTbaseUtil.getReferredVariable((VariableExp)asTarget);
RuleRegionImpl ruleRegion = (RuleRegionImpl)context.getRegion();
targetNode = ruleRegion.getNode(referredVariable);
if (targetNode != null) {
Map<@NonNull OCLExpression, @NonNull Node> expression2knownNode2 = expression2knownNode;
if (expression2knownNode2 == null) {
expression2knownNode = expression2knownNode2 = new HashMap<>();
}
expression2knownNode2.put(asSource, targetNode);
}
sourceNode = synthesize(asSource);
if (targetNode == sourceNode) {
return null;
}
else {
// scheduleManager.addRegionError(ruleRegion, "Failed to unify simple equality predicate " + operationCallExp);
targetNode = synthesize(asTarget);
}
}
else if (asSource instanceof NavigationCallExp) {
targetNode = synthesize(asTarget);
if (!targetNode.isDataType()) {
Map<@NonNull OCLExpression, @NonNull Node> expression2knownNode2 = expression2knownNode;
if (expression2knownNode2 == null) {
expression2knownNode = expression2knownNode2 = new HashMap<>();
}
expression2knownNode2.put(asSource, targetNode);
}
sourceNode = synthesize(asSource);
if (targetNode == sourceNode) {
return null;
}
// scheduleManager.addRegionError(ruleRegion, "Failed to unify simple equality predicate " + operationCallExp);
}
else {
sourceNode = synthesize(asSource);
if (!sourceNode.isDataType()) {
Map<@NonNull OCLExpression, @NonNull Node> expression2knownNode2 = expression2knownNode;
if (expression2knownNode2 == null) {
expression2knownNode = expression2knownNode2 = new HashMap<>();
}
expression2knownNode2.put(asTarget, sourceNode);
}
targetNode = synthesize(asTarget);
if (targetNode == sourceNode) {
return null;
}
// scheduleManager.addRegionError(ruleRegion, "Failed to unify simple equality predicate " + operationCallExp);
}
// createPredicateEdge(sourceNode, "«equals»", targetNode);
createEqualsEdge(targetNode, sourceNode);
return null;
}
private @Nullable Node synthesizeOperationCallExp_includes(@NonNull Node sourceNode, @NonNull OperationCallExp operationCallExp) {
Node targetNode = synthesize(operationCallExp.getOwnedArguments().get(0));
String name = operationCallExp.getReferredOperation().getName();
createPredicateEdge(sourceNode, "«" + name + "»", targetNode);
if (sourceNode.isDataType()) { // expecting a CollectionType
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(sourceNode)) {
if (edge instanceof NavigationEdge) {
NavigationEdge navigationEdge = (NavigationEdge)edge;
Property property = navigationEdge.getReferredProperty();
Property oppositeProperty = property.getOpposite();
if ((oppositeProperty != null) && !oppositeProperty.isIsMany()) {
createNavigationEdge(targetNode, oppositeProperty, QVTscheduleUtil.getSourceNode(navigationEdge), false);
}
}
}
}
return null;
}
private @NonNull Node synthesizeOperationCallExp_oclAsType(@NonNull Node sourceNode, @NonNull OperationCallExp operationCallExp) {
// if ((operationCallExp.getOwnedSource() instanceof CallExp) && sourceNode.refineClassDatumAnalysis(scheduler.getClassDatumAnalysis(operationCallExp))) {
// return sourceNode;
// }
ClassDatum castClassDatum = scheduleManager.getClassDatum(operationCallExp);
boolean castIsRequired = operationCallExp.isIsRequired();
// ClassDatum requiredClassDatum = environmentFactory.getCompleteModel().getCompleteClass(castType);
ClassDatum predicatedClassDatum = QVTscheduleUtil.getClassDatum(sourceNode);
boolean sourceIsRequired = sourceNode.isRequired();
if (QVTscheduleUtil.conformsTo(predicatedClassDatum, castClassDatum) && (sourceIsRequired || !castIsRequired)) {
sourceNode.addOriginatingElement(operationCallExp);
return sourceNode; // Skip cast if already conformant, typically a redundant cast daisy chain
}
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(sourceNode)) {
if (edge instanceof CastEdge) {
Node targetNode = edge.getEdgeTarget();
predicatedClassDatum = QVTscheduleUtil.getClassDatum(targetNode);
if (QVTscheduleUtil.conformsTo(predicatedClassDatum, castClassDatum)) {
targetNode.addOriginatingElement(operationCallExp);
return targetNode; // Re-use a pre-existing class
}
}
}
Type castType = QVTbaseUtil.getType(operationCallExp);
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(sourceNode)) {
if (edge instanceof CastEdge) {
CastEdge castEdge = (CastEdge)edge;
if (castClassDatum == castEdge.getReferredClassDatum()) {
Node castNode = castEdge.getEdgeTarget();
castNode.addOriginatingElement(operationCallExp);
return castNode;
}
}
}
// Edge castEdge = sourceNode.getPredicateEdge(castProperty);
// if (castEdge != null) {
// Node castNode = castEdge.getEdgeTarget();
// castNode.addOriginatingElement(operationCallExp);
// return castNode;
// }
String name = "a" + castType.getName();
// assert name != null;
Node castNode = createStepNode(name, operationCallExp, sourceNode);
if (castIsRequired) {
castNode.setRequired();
if ((castNode instanceof MappingNode) && sourceNode.isMatched()) {
((MappingNode)castNode).setMatched(true);
}
}
createCastEdge(sourceNode, castClassDatum, castNode);
OCLExpression argument = operationCallExp.getOwnedArguments().get(0);
if (!(argument instanceof TypeExp)) {
Node argumentNode = synthesize(argument);
// createExpressionEdge(argumentNode, "«arg»", castNode);
Operation referredOperation = QVTbaseUtil.getReferredOperation(operationCallExp);
Parameter firstParameter = QVTbaseUtil.getOwnedParameter(referredOperation, 0);
createOperationParameterEdge(argumentNode, firstParameter, -1, castNode);
}
return castNode;
/* OperationNode operationNode = new OperationNode(context, operationCallExp.getReferredOperation().getName(), context.getClassDatumAnalysis(operationCallExp));
QVTscheduleUtil.ARGUMENT.createEdge(context, sourceNode, "source", operationNode);
for (@SuppressWarnings("null")@NonNull OCLExpression argument : operationCallExp.getOwnedArguments()) {
Node argumentNode = analyze(argument);
QVTscheduleUtil.ARGUMENT.createEdge(context, argumentNode, "arg", operationNode);
}
Type returnType = operationCallExp.getType();
if (returnType instanceof DataType) {
return operationNode;
}
else {
// Variable resultVariable = PivotUtil.createVariable("-result-", returnType, operationCallExp.isIsRequired(), null);
// GuardNode resultNode = context.getGuardNode(resultVariable);
ClassDatumAnalysis classDatumAnalysis = scheduler.getClassDatumAnalysis(operationCallExp);
DomainClassNode resultNode = new DomainClassNode(context, "-result-", classDatumAnalysis);
// resultNode.setResult();
QVTscheduleUtil.ARGUMENT.createEdge(context, operationNode, null, resultNode);
return resultNode;
} */
}
/* private @NonNull Node synthesizeOperationCallExp_oclIsKindOf(@NonNull Node sourceNode, @NonNull OperationCallExp operationCallExp) {
Operation referredOperation = QVTbaseUtil.getReferredOperation(operationCallExp);
OCLExpression source = QVTbaseUtil.getOwnedSource(operationCallExp);
OCLExpression argument = QVTbaseUtil.getOwnedArgument(operationCallExp, 0);
Node operationNode = null;
if (argument instanceof TypeExp) {
// String name = referredOperation.getName() + "\\n" + ((TypeExp)argument).getReferredType().toString();
operationNode = findOperationNode(referredOperation, sourceNode);
if (operationNode == null) {
// operationNode = createConnectedOperationNode(name, nullArgNames, operationCallExp, sourceNode);
Type selfType = QVTbaseUtil.getType(source);
@NonNull Node @NonNull [] sourceAndArgumentNodes = new @NonNull Node[] { sourceNode };
boolean isMatched = QVTscheduleUtil.isMatched(operationCallExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
operationNode = nestedAnalyzer.createOperationCallNode(operationCallExp, referredOperation, sourceAndArgumentNodes);
nestedAnalyzer.createOperationSelfEdge(sourceAndArgumentNodes[0], selfType, operationNode);
}
}
else {
Node argumentNode = synthesize(argument);
operationNode = findOperationNode(referredOperation, sourceNode, argumentNode);
if (operationNode == null) {
Type selfType = QVTbaseUtil.getType(source);
Parameter parameter = QVTbaseUtil.getOwnedParameter(referredOperation, 0);
@NonNull Node[] sourceAndArgumentNodes = new @NonNull Node[] { sourceNode, argumentNode };
boolean isMatched = QVTscheduleUtil.isMatched(operationCallExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
operationNode = nestedAnalyzer.createOperationCallNode(operationCallExp, referredOperation, sourceAndArgumentNodes);
nestedAnalyzer.createOperationSelfEdge(sourceAndArgumentNodes[0], selfType, operationNode);
nestedAnalyzer.createOperationParameterEdge(sourceAndArgumentNodes[1], parameter, -1, operationNode);
}
}
return operationNode;
} */
private @NonNull Node synthesizeOperationCallExp_oclContainer(@NonNull Node sourceNode, @NonNull OperationCallExp operationCallExp) {
// Type castType = QVTbaseUtil.getType(operationCallExp);
Property oclContainerProperty = standardLibraryHelper.getOclContainerProperty();
Edge oclContainerEdge = sourceNode.getOutgoingPredicateEdge(oclContainerProperty);
if (oclContainerEdge != null) {
return oclContainerEdge.getEdgeTarget();
}
String name = QVTbaseUtil.getName(QVTbaseUtil.getReferredOperation(operationCallExp));
Node oclContainerNode = createStepNode(name, operationCallExp, sourceNode);
oclContainerEdge = createNavigationEdge(sourceNode, oclContainerProperty, oclContainerNode, false);
return oclContainerNode;
/* String name = operationCallExp.getReferredOperation().getName();
assert name != null;
Node operationNode = findOperationNode(sourceNode, name);
if (operationNode == null) {
operationNode = QVTscheduleUtil.OPERATION.createNode(context, name, operationCallExp, sourceNode);
QVTscheduleUtil.ARGUMENT.createEdge(context, sourceNode, null, operationNode);
}
return operationNode; */
/* Type type = operationCallExp.getType();
assert type != null;
Property oclContainerProperty = scheduler.getOclContainerProperty();
NavigationEdge navigationEdge = sourceNode.getNavigationEdge(oclContainerProperty);
if (navigationEdge != null) {
Node targetNode = navigationEdge.getTarget();
// if (targetNode instanceof ClassNode) {
return targetNode;
// }
// else {
// return null;
// }
}
String name = oclContainerProperty.getName();
assert (name != null) && (type != null);
FutureVariable variable = new FutureVariable("-container-", type, oclContainerProperty.isIsRequired(), sourceNode.getClassDatumAnalysis().getDomainUsage());
ClassNode targetReferenceNode = context.getReferenceNode(variable);
context.addPredicateEdge((ClassNode) sourceNode, oclContainerProperty, targetReferenceNode);
return targetReferenceNode; */
/* PredicateEdge predicateEdge = getPredicateEdge((ClassNode) sourceNode, oclContainerProperty);
if (predicateEdge != null) {
return predicateEdge.getTarget();
}
else {
AbstractRegion region = sourceNode.getRegion();
Node targetNode = new CastClassNode(region, (ClassNode) sourceNode, region.getClassDatum(operationCallExp));
addPredicateEdge((ClassNode) sourceNode, oclAsTypeProperty, targetNode);
return targetNode;
} */
}
@Override
public @NonNull Node visiting(@NonNull Visitable visitable) {
throw new UnsupportedOperationException(getClass().getSimpleName() + ": " + visitable.getClass().getSimpleName());
}
@Override
public @NonNull Node visitBooleanLiteralExp(@NonNull BooleanLiteralExp booleanLiteralExp) {
boolean booleanValue = booleanLiteralExp.isBooleanSymbol();
Node operationNode = createBooleanLiteralNode(booleanValue, booleanLiteralExp);
return operationNode;
}
@Override
public @NonNull Node visitCollectionLiteralExp(@NonNull CollectionLiteralExp collectionLiteralExp) {
List<@NonNull CollectionLiteralPart> ownedParts = QVTbaseUtil.Internal.getOwnedPartsList(collectionLiteralExp);
int iSize = ownedParts.size();
@NonNull Node [] partNodes = new @NonNull Node[iSize];
@NonNull CollectionLiteralPart [] collectionParts = new @NonNull CollectionLiteralPart[iSize];
for (int i = 0; i < iSize; i++) {
CollectionLiteralPart collectionPart = ownedParts.get(i);
partNodes[i] = synthesize(collectionPart);
collectionParts[i] = collectionPart;
}
boolean isMatched = QVTscheduleUtil.isMatched(collectionLiteralExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createCollectionLiteral(collectionLiteralExp, collectionParts, partNodes);
}
@Override
public @NonNull Node visitCollectionItem(@NonNull CollectionItem collectionItem) {
return synthesize(collectionItem.getOwnedItem());
}
@Override
public @NonNull Node visitCollectionRange(@NonNull CollectionRange collectionRange) {
Node firstNode = synthesize(collectionRange.getOwnedFirst());
Node lastNode = synthesize(collectionRange.getOwnedLast());
boolean isMatched = QVTscheduleUtil.isMatched(collectionRange);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createCollectionRange(collectionRange, firstNode, lastNode);
}
@Override
public @NonNull Node visitElement(@NonNull Element element) {
Class oclInvalidType = scheduleManager.getStandardLibrary().getOclInvalidType();
ClassDatum classDatum = scheduleManager.getClassDatum(scheduleManager.getDomainUsageAnalysis().getPrimitiveTypeModel(), oclInvalidType);
Node errorNode = createErrorNode("«error»", classDatum);
int parameterIndex = 0;
for (EObject eObject : element.eContents()) {
Node node = synthesize((Element) eObject);
// createExpressionEdge(node, "?", errorNode);
createOperationParameterEdge(node, qvtbaseLibraryHelper.getErrorElementsParameter(), parameterIndex++, errorNode);
}
return errorNode;
}
@Override
public @NonNull Node visitEnumLiteralExp(@NonNull EnumLiteralExp enumLiteralExp) {
EnumerationLiteral referredEnumerationLiteral = QVTbaseUtil.getReferredLiteral(enumLiteralExp);
Node operationNode = createEnumLiteralNode(referredEnumerationLiteral, enumLiteralExp);
return operationNode;
}
@Override
public @NonNull Node visitIfExp(@NonNull IfExp ifExp) {
ExpressionSynthesizer conditionalExpressionSynthesizer = getConditionalExpressionSynthesizer();
Node selfNode = synthesize(ifExp.getOwnedCondition());
Node thenNode = conditionalExpressionSynthesizer.synthesize(ifExp.getOwnedThen());
Node elseNode = conditionalExpressionSynthesizer.synthesize(ifExp.getOwnedElse());
boolean isMatched = QVTscheduleUtil.isMatched(ifExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createIf(ifExp, selfNode, thenNode, elseNode);
}
@Override
public @NonNull Node visitIntegerLiteralExp(@NonNull IntegerLiteralExp integerLiteralExp) {
Number numberValue = ClassUtil.nonNullState(integerLiteralExp.getIntegerSymbol());
Node operationNode = createNumericLiteralNode(numberValue, integerLiteralExp);
return operationNode;
}
@Override
public @NonNull Node visitLetExp(@NonNull LetExp letExp) {
Variable ownedVariable = letExp.getOwnedVariable();
Node initNode = synthesize(ownedVariable.getOwnedInit());
assert initNode != null;
ClassDatum actualClassDatum = QVTscheduleUtil.getClassDatum(initNode);
ClassDatum variableClassDatum = scheduleManager.getClassDatum(ownedVariable);
if (QVTscheduleUtil.conformsTo(actualClassDatum, variableClassDatum)) {
context.getRegion().addVariableNode(ownedVariable, initNode);
initNode.setOriginatingVariable(ownedVariable);
}
else {
Node varNode = createLetNode(ownedVariable, initNode);
createCastEdge(initNode, variableClassDatum, varNode);
}
return synthesize(letExp.getOwnedIn());
}
@Override
public @NonNull Node visitLoopExp(@NonNull LoopExp loopExp) {
Node sourceNode = synthesize(loopExp.getOwnedSource());
Node loopNode = doLoopExp(loopExp, sourceNode);
boolean isSafe = loopExp.isIsSafe();
if (isSafe) {
loopNode = doSafeNavigation(loopExp, sourceNode, loopNode);
}
return loopNode;
}
@Override
public @NonNull Node visitMapLiteralExp(@NonNull MapLiteralExp mapLiteralExp) {
List<@NonNull MapLiteralPart> ownedParts = QVTbaseUtil.Internal.getOwnedPartsList(mapLiteralExp);
int iSize = ownedParts.size();
@NonNull Node [] partNodes = new @NonNull Node[iSize];
@NonNull MapLiteralPart [] mapParts = new @NonNull MapLiteralPart[iSize];
for (int i = 0; i < iSize; i++) {
MapLiteralPart mapPart = ownedParts.get(i);
partNodes[i] = synthesize(mapPart);
mapParts[i] = mapPart;
}
boolean isMatched = QVTscheduleUtil.isMatched(mapLiteralExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createMapLiteral(mapLiteralExp, mapParts, partNodes);
}
@Override
public @NonNull Node visitMapLiteralPart(@NonNull MapLiteralPart mapLiteralPart) {
Node keyNode = synthesize(QVTbaseUtil.getOwnedKey(mapLiteralPart));
Node valueNode = synthesize(QVTbaseUtil.getOwnedValue(mapLiteralPart));
boolean isMatched = QVTscheduleUtil.isMatched(mapLiteralPart);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createMapPart(mapLiteralPart, keyNode, valueNode);
}
@Override
public @NonNull Node visitNavigationCallExp(@NonNull NavigationCallExp navigationCallExp) {
OCLExpression ownedSource = QVTbaseUtil.getOwnedSource(navigationCallExp);
Node sourceNode = synthesize(ownedSource);
Node navigationNode = doNavigationCallExp(navigationCallExp, sourceNode);
boolean isSafe = navigationCallExp.isIsSafe();
if (isSafe) {
navigationNode = doSafeNavigation(navigationCallExp, sourceNode, navigationNode);
}
return navigationNode;
}
@Override
public @NonNull Node visitNullLiteralExp(@NonNull NullLiteralExp nullLiteralExp) {
return createNullLiteralNode(nullLiteralExp);
}
@Override
public @NonNull Node visitOCLExpression(@NonNull OCLExpression oclExpression) {
return context.getUnknownNode(oclExpression);
}
@Override
public @Nullable Node visitOperationCallExp(@NonNull OperationCallExp operationCallExp) {
boolean isMatched = isRequired() || QVTscheduleUtil.isMatched(operationCallExp);
if (isUnconditional() && !isMatched) {
return getConditionalExpressionSynthesizer().visitOperationCallExp(operationCallExp);
}
OCLExpression ownedSource = operationCallExp.getOwnedSource();
if (ownedSource instanceof VariableExp) {
Transformation transformation = QVTbaseUtil.getContainingTransformation(operationCallExp);
Variable thisVariable = QVTbaseUtil.getContextVariable(scheduleManager.getStandardLibrary(), transformation);
if (((VariableExp)ownedSource).getReferredVariable() == thisVariable) {
ownedSource = null;
}
}
Node sourceNode = ownedSource != null ? synthesize(ownedSource) : null;
Node operationNode = doOperationCallExp(operationCallExp, sourceNode);
boolean isSafe = operationCallExp.isIsSafe();
if (isSafe && (sourceNode != null) && (operationNode != null)) {
operationNode = doSafeNavigation(operationCallExp, sourceNode, operationNode);
}
return operationNode;
}
@Override
public @NonNull Node visitRealLiteralExp(@NonNull RealLiteralExp realLiteralExp) {
Number numberValue = ClassUtil.nonNullState(realLiteralExp.getRealSymbol());
Node operationNode = createNumericLiteralNode(numberValue, realLiteralExp);
return operationNode;
}
@Override
public @NonNull Node visitShadowExp(@NonNull ShadowExp shadowExp) {
List<@NonNull ShadowPart> ownedParts = QVTbaseUtil.Internal.getOwnedPartsList(shadowExp);
int iSize = ownedParts.size();
@NonNull Node [] partNodes = new @NonNull Node[iSize];
@NonNull ShadowPart [] shadowParts = new @NonNull ShadowPart[iSize];
for (int i = 0; i < iSize; i++) {
ShadowPart shadowPart = ownedParts.get(i);
partNodes[i] = synthesize(shadowPart);
shadowParts[i] = shadowPart;
}
boolean isMatched = QVTscheduleUtil.isMatched(shadowExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createShadow(shadowExp, shadowParts, partNodes);
}
@Override
public @NonNull Node visitShadowPart(@NonNull ShadowPart shadowPart) {
return synthesize(shadowPart.getOwnedInit());
}
@Override
public @NonNull Node visitStringLiteralExp(@NonNull StringLiteralExp stringLiteralExp) {
String stringValue = ClassUtil.nonNullState(stringLiteralExp.getStringSymbol());
Node operationNode = createStringLiteralNode(stringValue, stringLiteralExp);
return operationNode;
}
@Override
public @NonNull Node visitTupleLiteralExp(@NonNull TupleLiteralExp tupleLiteralExp) {
List<@NonNull TupleLiteralPart> ownedParts = QVTbaseUtil.Internal.getOwnedPartsList(tupleLiteralExp);
int iSize = ownedParts.size();
@NonNull Node [] partNodes = new @NonNull Node[iSize];
@NonNull TupleLiteralPart [] tupleParts = new @NonNull TupleLiteralPart[iSize];
for (int i = 0; i < iSize; i++) {
TupleLiteralPart tuplePart = ownedParts.get(i);
partNodes[i] = synthesize(tuplePart);
tupleParts[i] = tuplePart;
}
boolean isMatched = QVTscheduleUtil.isMatched(tupleLiteralExp);
ExpressionSynthesizer nestedAnalyzer = isMatched ? this : getConditionalExpressionSynthesizer();
return nestedAnalyzer.createTupleLiteral(tupleLiteralExp, tupleParts, partNodes);
}
@Override
public @NonNull Node visitTupleLiteralPart(@NonNull TupleLiteralPart tupleLiteralPart) {
return synthesize(tupleLiteralPart.getOwnedInit());
}
@Override
public @NonNull Node visitTypeExp(@NonNull TypeExp typeExp) {
Type referredType = QVTbaseUtil.getReferredType(typeExp);
Node operationNode = createTypeLiteralNode(referredType, typeExp);
return operationNode;
}
@Override
public @NonNull Node visitVariableDeclaration(@NonNull VariableDeclaration variableDeclaration) {
return context.getReferenceNode(variableDeclaration);
}
@Override
public @NonNull Node visitVariableExp(@NonNull VariableExp variableExp) {
VariableDeclaration referredVariable = QVTbaseUtil.getReferredVariable(variableExp);
return context.getReferenceNode(referredVariable);
}
}