blob: 641e8e641399f6b66e2f5930425611acc601ec46 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - initial API and implementation
******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtr2qvtc;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.IteratorVariable;
import org.eclipse.ocl.pivot.LetVariable;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.osgi.util.NLS;
import org.eclipse.qvtd.compiler.CompilerChainException;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.analysis.RelationVariableAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.analysis.RelationVariableAnalysis.Strategy;
import org.eclipse.qvtd.pivot.qvtbase.Function;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtcore.Assignment;
import org.eclipse.qvtd.pivot.qvtcore.CorePattern;
import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment;
import org.eclipse.qvtd.pivot.qvtcore.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcore.VariableAssignment;
import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreUtil;
import org.eclipse.qvtd.pivot.qvtrelation.Key;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil;
import org.eclipse.qvtd.pivot.qvttemplate.ObjectTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp;
/**
* A RelationVariableAnalysis accumulates the usage of a relation variable and eventually synthesizes an appropriate core variable.
*/
public class RelationVariable2Variable extends AbstractVariable2Variable
{
private final @NonNull RelationVariableAnalysis variableAnalysis;
/**
* The corresponding synthesized core variable.
*/
private @Nullable Variable cVariable;
public RelationVariable2Variable(@NonNull Variables2Variables variablesAnalysis, @NonNull Variable rVariable) {
super(variablesAnalysis, QVTrelationUtil.getName(rVariable));
this.variableAnalysis = new RelationVariableAnalysis(variablesAnalysis, rVariable);
}
/**
* Add the NavigationAssignment "cVariable.cProperty := cExpression" to the cBottomPattern inverting the usage
* of a Collection element assignment to "cExpression.cOppositeProperty := cVariable".
* @throws CompilerChainException
*/
@Override
public void addNavigationAssignment(@NonNull Property targetProperty, @NonNull OCLExpression cExpression, @Nullable Boolean isPartial) throws CompilerChainException {
Key rKey = variableAnalysis.getrKey();
boolean isKeyed = variableAnalysis.getStrategy() == Strategy.KEYED;
if (isKeyed && (rKey != null)) {
if (rKey.getPart().contains(targetProperty)) {
return;
}
if (rKey.getOppositePart().contains(targetProperty.getOpposite())) {
return;
}
}
Variable cVariable2 = getCoreVariable();
List<@NonNull Assignment> cMiddleBottomAssignments = QVTcoreUtil.Internal.getOwnedAssignmentsList(variablesAnalysis.getMiddleBottomPattern());
if (isPartial == null) {
isPartial = targetProperty.isIsMany() && !(cExpression.getType() instanceof CollectionType);
}
// if (isPartial == isPartial2) {
VariableExp cSlotVariableExp = variablesAnalysis.createVariableExp(cVariable2);
NavigationAssignment cAssignment = variablesAnalysis.createNavigationAssignment(cSlotVariableExp, targetProperty, cExpression, isPartial);
QVTr2QVTc.SYNTHESIS.println(" addPropertyAssignment " + cAssignment);
variablesAnalysis.assertNewAssignment(cMiddleBottomAssignments, cAssignment);
cMiddleBottomAssignments.add(cAssignment);
return;
// }
/* Property cOppositeProperty = targetProperty.getOpposite();
if ((cOppositeProperty != null) && (cExpression instanceof VariableExp) && (!cOppositeProperty.isIsMany() || (cVariable2.getType() instanceof CollectionType))) {
VariableExp cSlotVariableExp = (VariableExp)cExpression;
NavigationAssignment cAssignment = variablesAnalysis.createNavigationAssignment(cSlotVariableExp, cOppositeProperty, variablesAnalysis.createVariableExp(cVariable2), isPartial);
QVTr2QVTc.SYNTHESIS.println(" addOppositePropertyAssignment " + cAssignment);
variablesAnalysis.assertNewAssignment(cMiddleBottomAssignments, cAssignment);
cMiddleBottomAssignments.add(cAssignment);
return;
} */
// throw new IllegalStateException("Unsupported collection assign " + cVariable2 + " . " + targetProperty + " := " + cExpression);
}
public @Nullable RealizedVariable basicGetCoreRealizedVariable() {
return (RealizedVariable)cVariable;
}
public @Nullable Variable basicGetCoreVariable() {
return cVariable;
}
@Override
public void check() {
boolean isRealized = variableAnalysis.getStrategy() == Strategy.REALIZED_BOTTOM;
if (variablesAnalysis.isAbstract() && isRealized) {
if (cVariable != null) {
System.err.println("cVariable for abstract " + this);
}
return;
}
if (cVariable == null) {
System.err.println("No cVariable for " + this);
return;
}
CorePattern cPattern = getCorePattern();
assert (cVariable != null) && ((cVariable.eContainer() == cPattern) || (cVariable instanceof IteratorVariable) || (cVariable instanceof LetVariable));
assert (cVariable instanceof RealizedVariable) == (isRealized && !(cVariable.getType() instanceof DataType));
}
@Override
public @NonNull CorePattern getCorePattern() {
/* Area cArea = null;
boolean isGuard = false;
if (cWhenDomain != null) {
isGuard = true;
// assert isEnforcedBound || (otherBound != null);
cArea = cWhenDomain; //isEnforcedBound ? cEnforcedDomain : otherBound;
}
// else if (isWhere) {
// }
else if (isEnforcedBound) {
isGuard = variablesAnalysis.isInvoked && isRoot; //rKey != null;
cArea = /*rKey != null ? variablesAnalysis.cMapping :* / variablesAnalysis.cEnforcedDomain;
}
else if (cOtherBound != null) {
isGuard = isRoot;
cArea = cOtherBound;
}
else if (isEnforcedReferred && (cOtherReferred != null)) {
isGuard = false;
cArea = variablesAnalysis.cMapping;
}
else if (cOtherReferred != null) {
isGuard = false;
cArea = cOtherReferred;
}
else if (cPredicateArea != null) {
isGuard = false;
cArea = cPredicateArea;
}
// else if (cThisArea != null) {
// isGuard = false;
// cArea = cThisArea;
// }
else if (isEnforcedReferred && (cOtherReferred == null)) {
isGuard = true;
cArea = variablesAnalysis.cEnforcedDomain;
}
assert cArea != null;
assert isGuard == (strategy2 == Strategy.ENFORCED_GUARD) || (strategy2 == Strategy.OTHER_GUARD);
CorePattern cPattern = null; */
Strategy strategy = variableAnalysis.getStrategy();
switch (strategy) {
case ENFORCED_BOTTOM:
return QVTcoreUtil.getBottomPattern(variablesAnalysis.cEnforcedDomain);
case ENFORCED_GUARD:
return QVTcoreUtil.getGuardPattern(variablesAnalysis.cEnforcedDomain);
case KEYED:
return QVTcoreUtil.getBottomPattern(variablesAnalysis.cEnforcedDomain);
case OTHER_BOTTOM:
return QVTcoreUtil.getBottomPattern(variablesAnalysis.getCoreDomain(getOtherTypedModel()));
case OTHER_GUARD:
return QVTcoreUtil.getGuardPattern(variablesAnalysis.getCoreDomain(getOtherTypedModel()));
case REALIZED_BOTTOM:
return QVTcoreUtil.getBottomPattern(variablesAnalysis.cEnforcedDomain);
case SHARED_BOTTOM:
return variablesAnalysis.cMiddleBottomPattern;
}
throw new IllegalStateException("A " + strategy + " variable has no CoreDomain");
}
@Override
public @NonNull Variable getCoreVariable() {
Variable cVariable2 = cVariable;
if (cVariable2 == null) {
cVariable2 = synthesize();
}
return cVariable2;
}
private @NonNull TypedModel getOtherTypedModel() throws IllegalStateException {
TypedModel rOtherBound = variableAnalysis.getrOtherBound();
if (rOtherBound != null) {
return rOtherBound;
}
TypedModel rOtherReferred = variableAnalysis.getrOtherReferred();
if (rOtherReferred != null) {
return rOtherReferred;
}
TypedModel rPredicate = variableAnalysis.getrPredicate();
if (rPredicate != null) {
return rPredicate;
}
TypedModel rWhenTypedModel = variableAnalysis.getrWhenTypedModel();
if (rWhenTypedModel != null) {
return rWhenTypedModel;
}
TypedModel rWhereTypedModel = variableAnalysis.getrWhereTypedModel();
if (rWhereTypedModel != null) {
return rWhereTypedModel;
}
throw new IllegalStateException("Failed to determine other pattern for " + this);
}
@Override
public @Nullable Variable getRelationVariable() {
return variableAnalysis.getRelationVariable();
}
@Override
public boolean hasWhenDomain() {
return variableAnalysis.hasWhenDomain();
}
private void initializeKeyedVariable(@NonNull Variable cKeyedVariable) {
TypedModel rEnforcedTypedModel2 = ClassUtil.nonNull(variableAnalysis.getrEnforcedTypedModel());
Key rKey2 = ClassUtil.nonNull(variableAnalysis.getrKey());
Function function = variablesAnalysis.getRelationAnalysis().getTransformationAnalysis().getKeyFunction(rEnforcedTypedModel2, rKey2);
List<@NonNull OCLExpression> asArguments = new ArrayList<@NonNull OCLExpression>();
TemplateExp rTemplateExp = variableAnalysis.getrTemplateExp();
if (rTemplateExp instanceof ObjectTemplateExp) {
ObjectTemplateExp objectTemplateExp = (ObjectTemplateExp)rTemplateExp;
for (@NonNull Parameter keyParameter : ClassUtil.nullFree(function.getOwnedParameters())) {
OCLExpression parameterExp = variablesAnalysis.getTemplateExp(objectTemplateExp, keyParameter);
if (parameterExp instanceof TemplateExp) {
Variable rVariable = ClassUtil.nonNullState(((TemplateExp)parameterExp).getBindsTo());
Variable cVariable = variablesAnalysis.getCoreVariable(rVariable);
asArguments.add(variablesAnalysis.createVariableExp(cVariable));
}
else if (parameterExp instanceof VariableExp) {
Variable rVariable = (Variable) ClassUtil.nonNullState(((VariableExp)parameterExp).getReferredVariable());
Variable cVariable = variablesAnalysis.getCoreVariable(rVariable);
asArguments.add(variablesAnalysis.createVariableExp(cVariable));
}
else {
throw new IllegalStateException(NLS.bind("Missing ''{1}'' value for ''{0}'' key.", rKey2.getIdentifies().getName(), keyParameter.getName()));
// asArguments.add(variablesAnalysis.createInvalidExpression());
}
}
}
Variable cThisVariable = variablesAnalysis.getCoreThisVariable();
OCLExpression asConstructor = variablesAnalysis.createOperationCallExp(variablesAnalysis.createVariableExp(cThisVariable), function, asArguments);
// addConditionPredicate(cMiddleBottomPattern, createVariableExp(cKeyedVariable), asConstructor);
@NonNull VariableAssignment cVariableAssignment = variablesAnalysis.createVariableAssignment(cKeyedVariable, asConstructor);
variablesAnalysis.getMiddleBottomPattern().getAssignment().add(cVariableAssignment);
}
@Override
public boolean isRealized() {
return variableAnalysis.isRealized();
}
@Override
public void setIsEnforcedBound(@Nullable TemplateExp rTemplateExp, @NonNull TypedModel rEnforcedTypedModel, @Nullable Key rKey) {
variableAnalysis.setIsEnforcedBound(rTemplateExp, rEnforcedTypedModel, rKey);
}
@Override
public void setIsEnforcedReferred() {
variableAnalysis.setIsEnforcedReferred();
}
@Override
public void setIsRoot() {
variableAnalysis.setIsRoot();
}
@Override
public void setOtherBound(@NonNull TypedModel rOtherTypedModel) {
variableAnalysis.setOtherBound(rOtherTypedModel);
}
@Override
public void setOtherReferred(@NonNull TypedModel rOtherTypedModel) {
variableAnalysis.setOtherReferred(rOtherTypedModel);
}
@Override
public void setPredicate(@NonNull TypedModel rPredicateTypedModel) {
variableAnalysis.setPredicate(rPredicateTypedModel);
}
@Override
public void setWhen(@NonNull TypedModel rWhenTypedModel) {
variableAnalysis.setWhen(rWhenTypedModel);
}
@Override
public void setWhere(@NonNull TypedModel rWhereTypedModel) {
variableAnalysis.setWhere(rWhereTypedModel);
}
protected @NonNull Variable synthesize() {
Variable cVariable2 = cVariable;
if (cVariable2 == null) {
Strategy strategy = variableAnalysis.getStrategy();
Variable rVariable = variableAnalysis.getRelationVariable();
Type type = QVTrelationUtil.getType(rVariable);
switch (strategy) {
case ENFORCED_BOTTOM: {
cVariable2 = variablesAnalysis.createBottomVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.cEnforcedDomain.getBottomPattern().getVariable().add(cVariable2);
break;
}
case ENFORCED_GUARD: {
cVariable2 = variablesAnalysis.createGuardVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.cEnforcedDomain.getGuardPattern().getVariable().add(cVariable2);
break;
}
case KEYED: {
cVariable2 = variablesAnalysis.createBottomVariable(name, type, true, null);
initializeKeyedVariable(cVariable2); // FIXME can recurse - is stability guaranteed?
variablesAnalysis.cEnforcedDomain.getBottomPattern().getVariable().add(cVariable2);
break;
}
case OTHER_BOTTOM: {
cVariable2 = variablesAnalysis.createBottomVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.getCoreDomain(getOtherTypedModel()).getBottomPattern().getVariable().add(cVariable2);
break;
}
case OTHER_GUARD: {
cVariable2 = variablesAnalysis.createGuardVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.getCoreDomain(getOtherTypedModel()).getGuardPattern().getVariable().add(cVariable2);
break;
}
case REALIZED_BOTTOM: {
if (variablesAnalysis.isAbstract()) {
throw new IllegalStateException();
}
else if ((type instanceof CollectionType)) {
cVariable2 = variablesAnalysis.createBottomVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.cEnforcedDomain.getBottomPattern().getVariable().add(cVariable2);
}
else {
RealizedVariable cRealizedVariable = variablesAnalysis.createRealizedVariable(name, type);
variablesAnalysis.cEnforcedDomain.getBottomPattern().getRealizedVariable().add(cRealizedVariable);
cVariable2 = cRealizedVariable;
}
break;
}
case SHARED_BOTTOM: {
cVariable2 = variablesAnalysis.createBottomVariable(name, type, rVariable.isIsRequired(), null);
variablesAnalysis.cMiddleBottomPattern.getVariable().add(cVariable2);
break;
}
default: {
throw new IllegalStateException("Failed to identify strategy for variable " + this);
}
}
cVariable = cVariable2;
variablesAnalysis.addVariableAnalysis(this);
}
return cVariable2;
}
}