diff options
author | Ed Willink | 2017-03-07 08:56:19 +0000 |
---|---|---|
committer | Ed Willink | 2017-03-11 10:47:37 +0000 |
commit | 351b5903016b50dd7c9d41fb3530dab3ff379fab (patch) | |
tree | caefe40634f2666e3d7feea06b1ae42284cecb00 | |
parent | 19ff65d7a26f24828a0320c05182b3898cfd0c3e (diff) | |
download | org.eclipse.qvtd-351b5903016b50dd7c9d41fb3530dab3ff379fab.tar.gz org.eclipse.qvtd-351b5903016b50dd7c9d41fb3530dab3ff379fab.tar.xz org.eclipse.qvtd-351b5903016b50dd7c9d41fb3530dab3ff379fab.zip |
wip success property
4 files changed, 484 insertions, 232 deletions
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/AbstractQVTr2QVTcRelations.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/AbstractQVTr2QVTcRelations.java index 1d6686117..7fa51be58 100644 --- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/AbstractQVTr2QVTcRelations.java +++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/AbstractQVTr2QVTcRelations.java @@ -21,6 +21,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.ocl.pivot.Class; import org.eclipse.ocl.pivot.CollectionLiteralExp; import org.eclipse.ocl.pivot.CollectionLiteralPart; import org.eclipse.ocl.pivot.CollectionType; @@ -37,7 +38,6 @@ import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.PivotUtil; import org.eclipse.qvtd.compiler.CompilerChainException; -import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.InvokedRelationToMappingForEnforcement.InvokedEnforceableRelationDomain2CoreMapping; import org.eclipse.qvtd.pivot.qvtbase.Domain; import org.eclipse.qvtd.pivot.qvtbase.Pattern; import org.eclipse.qvtd.pivot.qvtbase.Predicate; @@ -414,7 +414,10 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; @Override public EObject copy(EObject oIn) { try { - if (oIn instanceof IteratorVariable) { + if (oIn instanceof RelationCallExp) { + return mapRelationCallExpToAndExpression((RelationCallExp)oIn); + } + else if (oIn instanceof IteratorVariable) { return variablesAnalysis.getCoreVariable((IteratorVariable)oIn); } else if (oIn instanceof LetVariable) { @@ -525,7 +528,7 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; */ private final @NonNull Map<@NonNull Element, @NonNull Element> target2source = new HashMap<>(); - public AbstractEnforceableRelationDomain2CoreMapping(@NonNull RelationDomain rEnforcedDomain, @NonNull String cMappingName) throws CompilerChainException { + public AbstractEnforceableRelationDomain2CoreMapping(@NonNull RelationDomain rEnforcedDomain, @NonNull String cMappingName, @NonNull Class traceClass) throws CompilerChainException { this.rEnforcedDomain = rEnforcedDomain; // this.rEnforcedBoundVariables = VariablesAnalysis.gatherBoundVariables(rEnforcedDomain); @@ -537,7 +540,6 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; this.rEnforcedRootVariables = QVTrelationUtil.getRootVariables(rEnforcedDomain); this.rEnforcedTypedModel = QVTrelationUtil.getTypedModel(rEnforcedDomain); this.rEnforcedDomainName = ClassUtil.nonNullState(rEnforcedDomain.getName()); - @NonNull Type traceClass = qvtr2qvtc.getTraceClass(rRelation); // this.cEnforcedTypedModel = getCoreTypedModel(rEnforcedTypedModel); this.cMapping = qvtr2qvtc.createMapping(rRelation, cMappingName); @@ -547,7 +549,7 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; this.cEnforcedGuardPattern = ClassUtil.nonNullState(cEnforcedDomain.getGuardPattern()); this.cEnforcedBottomPattern = ClassUtil.nonNullState(cEnforcedDomain.getBottomPattern()); // - this.variablesAnalysis = new VariablesAnalysis(qvtr2qvtc, rEnforcedDomain, cEnforcedDomain, traceClass, this instanceof InvokedEnforceableRelationDomain2CoreMapping); + this.variablesAnalysis = new VariablesAnalysis(qvtr2qvtc, rEnforcedDomain, cEnforcedDomain, traceClass, getWhenInvocations(), getWhereInvocations()); this.cMiddleRealizedVariable = variablesAnalysis.getMiddleRealizedVariable(); // putTrace(cMiddleRealizedVariable, cMiddleBottomPattern); // @@ -727,6 +729,18 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; return rTemplateExpressions; } + private boolean isEnforced(@NonNull Variable rParameter) { + Relation rRelation = QVTrelationUtil.getContainingRelation(rParameter); + for (@NonNull RelationDomain rDomain : QVTrelationUtil.getOwnedDomains(rRelation)) { + for (@NonNull Variable rootVariable : QVTrelationUtil.getRootVariables(rDomain)) { + if (rootVariable == rParameter) { + return rDomain.getTypedModel() == rEnforcedTypedModel; + } + } + } + return false; + } + private boolean isVarBoundToSomeOtherTemplate(ObjectTemplateExp rootTe, /*Object*/TemplateExp skipTe, Variable v) { if (rootTe == skipTe) { return false; @@ -1057,6 +1071,36 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; } } + protected void mapRelationCallExpToPattern(@NonNull RelationCallExp rInvocation) throws CompilerChainException { + // body of RWhenRelCallToMGuard + Relation rInvokedRelation = QVTrelationUtil.getReferredRelation(rInvocation); + Type invokedTraceClass/*tc*/ = qvtr2qvtc.getTraceClass(rInvokedRelation); // ?? invocation + // + List<@NonNull OCLExpression> rArguments = QVTrelationUtil.Internal.getOwnedArgumentsList(rInvocation); + /* StringBuilder s = new StringBuilder(); + for (OCLExpression rArgument : rArguments) { + VariableExp a = (VariableExp) rArgument; + s.append("_"); + s.append(a.getReferredVariable().getName()); + } + String vdId = s.toString(); */ + String invokedName = "when_" + invokedTraceClass.getName()/* + vdId*/; + Variable cCalledVariable/*vd*/ = variablesAnalysis.addCoreGuardVariable(invokedName, invokedTraceClass); // FIXME + List<@NonNull Variable> rParameters = qvtr2qvtc.getRootVariables(rInvokedRelation); + int iSize = rArguments.size(); + assert iSize == rParameters.size(); + for (int i = 0; i < iSize; i++) { + VariableExp rArgument/*ve*/ = (VariableExp) rArguments.get(i); + Variable rParameter/*dv*/ = rParameters.get(i); + //RWhenRelCallArgToMGuardPredicate + Variable rArgumentVariable/*v*/ = QVTbaseUtil.getReferredVariable(rArgument); + Variable cArgumentVariable/*mv*/ = variablesAnalysis.getCoreVariable(rArgumentVariable); + Property cCalledProperty/*pep*/ = qvtr2qvtc.getProperty(cCalledVariable.getType(), rParameter); + NavigationCallExp cCalledValue/*pe*/ = createNavigationCallExp(createVariableExp(cCalledVariable), cCalledProperty); + variablesAnalysis.addConditionPredicate(cMiddleGuardPattern, cCalledValue, createVariableExp(cArgumentVariable)); + } + } + // protected @NonNull Variable mapRealizedVariable(@NonNull Variable rVariable) { // return whenRealizedVariable(cEnforcedBottomPattern, rVariable); // } @@ -1086,37 +1130,10 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; Set<@NonNull Variable> rMiddleGuardDomainVariables = new HashSet<>(rWhenVariable2rTypedModel.keySet()); rMiddleGuardDomainVariables.removeAll(rAllVariables); // - for (@NonNull Predicate rWhenPredicate : QVTrelationUtil.getPredicates(rWhenPattern)) { + for (@NonNull Predicate rWhenPredicate : QVTrelationUtil.getOwnedPredicates(rWhenPattern)) { OCLExpression rConditionExpression = QVTrelationUtil.getConditionExpression(rWhenPredicate); if (rConditionExpression instanceof RelationCallExp) { - // body of RWhenRelCallToMGuard - RelationCallExp rInvocation = (RelationCallExp)rConditionExpression; - Relation rInvokedRelation = QVTrelationUtil.getReferredRelation(rInvocation); - Type invokedTraceClass/*tc*/ = qvtr2qvtc.getTraceClass(rInvokedRelation); - // - List<@NonNull OCLExpression> rArguments = QVTrelationUtil.Internal.getOwnedArgumentsList(rInvocation); - /* StringBuilder s = new StringBuilder(); - for (OCLExpression rArgument : rArguments) { - VariableExp a = (VariableExp) rArgument; - s.append("_"); - s.append(a.getReferredVariable().getName()); - } - String vdId = s.toString(); */ - String invokedName = "when_" + invokedTraceClass.getName()/* + vdId*/; - Variable cCalledVariable/*vd*/ = variablesAnalysis.addCoreGuardVariable(invokedName, invokedTraceClass); // FIXME - List<@NonNull Variable> rParameters = qvtr2qvtc.getRootVariables(rInvokedRelation); - int iSize = rArguments.size(); - assert iSize == rParameters.size(); - for (int i = 0; i < iSize; i++) { - VariableExp rArgument/*ve*/ = (VariableExp) rArguments.get(i); - Variable rParameter/*dv*/ = rParameters.get(i); - //RWhenRelCallArgToMGuardPredicate - Variable rArgumentVariable/*v*/ = QVTbaseUtil.getReferredVariable(rArgument); - Variable cArgumentVariable/*mv*/ = variablesAnalysis.getCoreVariable(rArgumentVariable); - Property cCalledProperty/*pep*/ = qvtr2qvtc.getProperty(cCalledVariable.getType(), rParameter); - NavigationCallExp cCalledValue/*pe*/ = createNavigationCallExp(createVariableExp(cCalledVariable), cCalledProperty); - variablesAnalysis.addConditionPredicate(cMiddleGuardPattern, cCalledValue, createVariableExp(cArgumentVariable)); - } + mapRelationCallExpToPattern((RelationCallExp)rConditionExpression); } else { // body of RSimplePatternToMPattern @@ -1131,6 +1148,51 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; } } + protected @NonNull OperationCallExp mapRelationCallExpToAndExpression(@NonNull RelationCallExp rInvocation) throws CompilerChainException { + // body of RWhenRelCallToMGuard + Relation rInvokedRelation = QVTrelationUtil.getReferredRelation(rInvocation); + Type invokedTraceClass/*tc*/ = qvtr2qvtc.getTraceClass(rInvokedRelation); // ?? invocation + // + List<@NonNull OCLExpression> rArguments = QVTrelationUtil.Internal.getOwnedArgumentsList(rInvocation); + /* StringBuilder s = new StringBuilder(); + for (OCLExpression rArgument : rArguments) { + VariableExp a = (VariableExp) rArgument; + s.append("_"); + s.append(a.getReferredVariable().getName()); + } + String vdId = s.toString(); */ + String invokedName = "when_" + invokedTraceClass.getName()/* + vdId*/; + Variable cCalledVariable/*vd*/ = variablesAnalysis.addCoreGuardVariable(invokedName, invokedTraceClass); // FIXME + List<@NonNull Variable> rParameters = qvtr2qvtc.getRootVariables(rInvokedRelation); + int iSize = rArguments.size(); + assert iSize == rParameters.size(); + OperationCallExp result = null; + for (int i = 0; i < iSize; i++) { + VariableExp rArgument/*ve*/ = (VariableExp) rArguments.get(i); + Variable rParameter/*dv*/ = rParameters.get(i); + Property cCalledProperty/*pep*/ = qvtr2qvtc.getProperty(cCalledVariable.getType(), rParameter); + Variable rArgumentVariable/*v*/ = QVTbaseUtil.getReferredVariable(rArgument); + Variable cArgumentVariable/*mv*/ = variablesAnalysis.getCoreVariable(rArgumentVariable); + if (isEnforced(rParameter)) { + //RWhenRelCallArgToMGuardPredicate + NavigationCallExp cCalledValue/*pe*/ = createNavigationCallExp(createVariableExp(cCalledVariable), cCalledProperty); + OperationCallExp eTerm = createOperationCallExp(cCalledValue, "=", createVariableExp(cArgumentVariable)); + if (result == null) { + result = eTerm; + } + else { + result = createOperationCallExp(result, "and", eTerm); + } + } + else { + NavigationCallExp cCalledValue/*pe*/ = createNavigationCallExp(createVariableExp(cCalledVariable), cCalledProperty); + variablesAnalysis.addConditionPredicate(cMiddleGuardPattern, cCalledValue, createVariableExp(cArgumentVariable)); + } + } + assert result != null; + return result; + } + // RPredicateSetToMBPredicateSet protected void mapWhereBottomPredicates(@NonNull Iterable<@NonNull Predicate> rWherePredicates) throws CompilerChainException { for (@NonNull Predicate rWherePredicate : rWherePredicates) { @@ -1292,7 +1354,7 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; VariablesAnalysis.gatherReferredVariablesWithTypedModels(rWhenVariable2rTypedModel, rWhenPattern); // FIXME assert rWhenPattern.getBindsTo().equals(rWhenVariables); // rWhenPattern.getBindsTo().addAll(rWhenVariables); - for (@NonNull Predicate rWhenPredicate : QVTrelationUtil.getPredicates(rWhenPattern)) { + for (@NonNull Predicate rWhenPredicate : QVTrelationUtil.getOwnedPredicates(rWhenPattern)) { if (!(rWhenPredicate.getConditionExpression() instanceof RelationCallExp)) { // FIXME Eliminate this redundant distinction rWhenPredicates.add(rWhenPredicate); } @@ -1306,7 +1368,7 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; VariablesAnalysis.gatherReferredVariablesWithTypedModels(rWhereVariable2rTypedModel, rWherePattern); // FIXME assert rWherePattern.getBindsTo().equals(rWhereVariables); // rWherePattern.getBindsTo().addAll(rWhereVariables); - for (@NonNull Predicate rWherePredicate : QVTrelationUtil.getPredicates(rWherePattern)) { + for (@NonNull Predicate rWherePredicate : QVTrelationUtil.getOwnedPredicates(rWherePattern)) { if (!(rWherePredicate.getConditionExpression() instanceof RelationCallExp)) { rWherePredicates.add(rWherePredicate); } @@ -1332,6 +1394,14 @@ import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp; */ protected abstract @NonNull List<@NonNull ? extends AbstractEnforceableRelationDomain2CoreMapping> analyze() throws CompilerChainException; + protected @Nullable Iterable<@NonNull RelationCallExp> getWhenInvocations() { + return null; + } + + protected @Nullable Iterable<@NonNull RelationCallExp> getWhereInvocations() { + return null; + } + @Override public @NonNull String toString() { return PivotUtil.getName(rTransformation) + "::" + rRelationName; diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTr2QVTc.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTr2QVTc.java index f37f5b65d..523655095 100644 --- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTr2QVTc.java +++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTr2QVTc.java @@ -210,9 +210,19 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc private final @NonNull Map<@NonNull Relation, org.eclipse.ocl.pivot.@NonNull Class> relation2traceClass = new HashMap<>(); /** - * Map from each relation to all the expressions that call the relation. + * Mapping from each relation to its corresponding trace class. + */ + private final @NonNull Map<@NonNull RelationCallExp, org.eclipse.ocl.pivot.@NonNull Class> invocation2traceClass = new HashMap<>(); + + /** + * Map from each relation to all the expressions that call the relationfrom a where clause. + */ + private final @NonNull Map<@NonNull Relation, @Nullable List<@NonNull RelationCallExp>> relation2whenInvocations = new HashMap<>(); + + /** + * Map from each relation to all the expressions that call the relationfrom a when clause. */ - private final @NonNull Map<@NonNull Relation, @NonNull List<@NonNull RelationCallExp>> relation2invocations = new HashMap<>(); + private final @NonNull Map<@NonNull Relation, @Nullable List<@NonNull RelationCallExp>> relation2whereInvocations = new HashMap<>(); /** * Map from each relation invocation the relation whose where predicate contains the invocation. @@ -284,21 +294,30 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc } protected void analyzeInvocations(@NonNull Relation callingRelation) { + Pattern whenPattern = callingRelation.getWhen(); + if (whenPattern != null) { + analyzeInvocations(callingRelation, whenPattern, relation2whenInvocations); + } Pattern wherePattern = callingRelation.getWhere(); if (wherePattern != null) { - for (Predicate predicate : wherePattern.getPredicate()) { - OCLExpression predicateExpression = predicate.getConditionExpression(); - if (predicateExpression instanceof RelationCallExp) { - RelationCallExp relationInvocation = (RelationCallExp) predicateExpression; - Relation calledRelation = ClassUtil.nonNullState(relationInvocation.getReferredRelation()); - List<@NonNull RelationCallExp> relationInvocations = relation2invocations.get(calledRelation); - if (relationInvocations == null) { - relationInvocations = new ArrayList<>(); - relation2invocations.put(calledRelation, relationInvocations); - } - relationInvocations.add(relationInvocation); - invocation2invokingRelation.put(relationInvocation, callingRelation); + analyzeInvocations(callingRelation, wherePattern, relation2whereInvocations); + } + } + + protected void analyzeInvocations(@NonNull Relation callingRelation, @NonNull Pattern pattern, + @NonNull Map<@NonNull Relation, @Nullable List<@NonNull RelationCallExp>> relation2invocations2) { + for (Predicate predicate : pattern.getPredicate()) { + OCLExpression predicateExpression = predicate.getConditionExpression(); + if (predicateExpression instanceof RelationCallExp) { + RelationCallExp relationInvocation = (RelationCallExp) predicateExpression; + Relation calledRelation = ClassUtil.nonNullState(relationInvocation.getReferredRelation()); + List<@NonNull RelationCallExp> relationInvocations = relation2invocations2.get(calledRelation); + if (relationInvocations == null) { + relationInvocations = new ArrayList<>(); + relation2invocations2.put(calledRelation, relationInvocations); } + relationInvocations.add(relationInvocation); + invocation2invokingRelation.put(relationInvocation, callingRelation); } } } @@ -369,9 +388,14 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc name2mapping = new HashMap<>(); transformation2name2mapping.put(cTransformation, name2mapping); } + String distinctName = name; Mapping coreMapping = name2mapping.get(name); - assert (coreMapping == null);// { - coreMapping = helper.createMapping(name); + int suffix = 0; + while (coreMapping != null) { + distinctName = name + ++suffix; + coreMapping = name2mapping.get(distinctName); + } + coreMapping = helper.createMapping(distinctName); putGlobalTrace(coreMapping, relation); coreMapping.setTransformation(cTransformation); name2mapping.put(name, coreMapping); @@ -611,11 +635,6 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc return qvtcResource; } - public @NonNull List<@NonNull RelationCallExp> getRelationCallExpsForRelation(@NonNull Relation relation) { - List<@NonNull RelationCallExp> invocations = relation2invocations.get(relation); - return invocations != null ? invocations : Collections.emptyList(); - } - public @NonNull List<@NonNull Variable> getRootVariables(@NonNull Relation relation) { return ClassUtil.nonNullState(relation2rootVariables.get(relation)); } @@ -632,10 +651,22 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc return ClassUtil.nonNullState(relation2traceClass.get(relation)); } + /*public*/ org.eclipse.ocl.pivot.@NonNull Class getTraceClass(@NonNull RelationCallExp invocation) { + return ClassUtil.nonNullState(invocation2traceClass.get(invocation)); + } + /*public*/ org.eclipse.ocl.pivot.@NonNull Package getTracePackage(@NonNull RelationalTransformation rTransformation) { return ClassUtil.nonNullState(rTransformation2tracePackage.get(rTransformation)); } + public @Nullable Iterable<@NonNull RelationCallExp> getWhenRelationCallExpsForRelation(@NonNull Relation relation) { + return relation2whenInvocations.get(relation); + } + + public @Nullable Iterable<@NonNull RelationCallExp> getWhereRelationCallExpsForRelation(@NonNull Relation relation) { + return relation2whereInvocations.get(relation); + } + protected void mapQueries(@NonNull RelationalTransformation rTransformation, @NonNull Transformation cTransformation) { List<@NonNull Operation> cOperations = new ArrayList<>(); for (@NonNull Operation rOperation : QVTbaseUtil.getOwnedOperations(rTransformation)) { @@ -679,7 +710,9 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc } for (@NonNull Relation rRelation : rRelations) { if (!rRelation.isIsTopLevel()) { - InvokedRelationToMappingForEnforcement invokedRelationToMappingForEnforcement = new InvokedRelationToMappingForEnforcement(this, rRelation); + Iterable<@NonNull RelationCallExp> whenInvocations = relation2whenInvocations.get(rRelation); + Iterable<@NonNull RelationCallExp> whereInvocations = relation2whereInvocations.get(rRelation); + InvokedRelationToMappingForEnforcement invokedRelationToMappingForEnforcement = new InvokedRelationToMappingForEnforcement(this, rRelation, whenInvocations, whereInvocations); invokedRelationToMappingForEnforcement.transform(); } } @@ -725,6 +758,12 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc // } } + /*public*/ void putInvocationTrace(@NonNull RelationCallExp rInvocation, org.eclipse.ocl.pivot.@NonNull Class traceClass) { + org.eclipse.ocl.pivot.Class oldTraceClass = invocation2traceClass.put(rInvocation, traceClass); + assert oldTraceClass == null; + // putTrace(traceClass, r); + } + /*public*/ void putRelationTrace(@NonNull Relation rRelation, org.eclipse.ocl.pivot.@NonNull Class traceClass) { org.eclipse.ocl.pivot.Class oldTraceClass = relation2traceClass.put(rRelation, traceClass); assert oldTraceClass == null; @@ -993,7 +1032,7 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc } } - public void transformToTracePackages() { + public void transformToTracePackages() throws CompilerChainException { List<org.eclipse.ocl.pivot.@NonNull Package> rootTracePackages = null; for (@NonNull EObject eObject : qvtrResource.getContents()) { if (eObject instanceof RelationModel) { @@ -1011,14 +1050,14 @@ public class QVTr2QVTc extends AbstractQVTc2QVTc } } - private @Nullable List<org.eclipse.ocl.pivot.@NonNull Package> transformToTracePackageHierarchy(@NonNull Iterable<org.eclipse.ocl.pivot.@NonNull Package> relationPackages) { + private @Nullable List<org.eclipse.ocl.pivot.@NonNull Package> transformToTracePackageHierarchy(@NonNull Iterable<org.eclipse.ocl.pivot.@NonNull Package> relationPackages) throws CompilerChainException { List<org.eclipse.ocl.pivot.@NonNull Package> nestingTracePackages = null; for (org.eclipse.ocl.pivot.@NonNull Package relationPackage : relationPackages) { List<org.eclipse.ocl.pivot.@NonNull Package> nestedTracePackages = null; for (org.eclipse.ocl.pivot.@NonNull Class relationClass : ClassUtil.nullFree(relationPackage.getOwnedClasses())) { if (relationClass instanceof RelationalTransformation) { - RelationalTransformationToTracePackage rTransformationToTracePackage = new RelationalTransformationToTracePackage(this); - org.eclipse.ocl.pivot.Package nestedTracePackage = rTransformationToTracePackage.doRelationalTransformationToTracePackage((RelationalTransformation)relationClass); + RelationalTransformationToTracePackage rTransformationToTracePackage = new RelationalTransformationToTracePackage(this, (RelationalTransformation)relationClass); + org.eclipse.ocl.pivot.Package nestedTracePackage = rTransformationToTracePackage.transform(); txTracePackages.add(nestedTracePackage); if (nestedTracePackages == null) { nestedTracePackages = new ArrayList<>(); diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTrNameGenerator.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTrNameGenerator.java index bdf3dcae7..a0350628c 100644 --- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTrNameGenerator.java +++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/QVTrNameGenerator.java @@ -25,6 +25,7 @@ public class QVTrNameGenerator public static final @NonNull String IDENTIFIED_INSTANCE_VARIABLE_NAME = "identifiedInstance"; public static final @NonNull String KEYED_INSTANCE_PROPERTY_NAME = "instance"; public static final @NonNull String KEY2INSTANCE_VARIABLE_NAME = "key2instance"; + public static final @NonNull String TRACECLASS_SUCCESS_PROPERTY_NAME = "_success"; protected final @NonNull QVTr2QVTc qvtr2qvtc; diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/RelationalTransformationToTracePackage.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/RelationalTransformationToTracePackage.java index e16c8d1f8..19e606bc2 100644 --- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/RelationalTransformationToTracePackage.java +++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtr2qvtc/RelationalTransformationToTracePackage.java @@ -10,8 +10,13 @@ ******************************************************************************/ package org.eclipse.qvtd.compiler.internal.qvtr2qvtc; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; @@ -29,11 +34,11 @@ import org.eclipse.ocl.pivot.VariableDeclaration; import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.TreeIterable; +import org.eclipse.qvtd.compiler.CompilerChainException; import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil; import org.eclipse.qvtd.pivot.qvtbase.Domain; import org.eclipse.qvtd.pivot.qvtbase.Pattern; import org.eclipse.qvtd.pivot.qvtbase.Predicate; -import org.eclipse.qvtd.pivot.qvtbase.Rule; import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern; import org.eclipse.qvtd.pivot.qvtrelation.Relation; import org.eclipse.qvtd.pivot.qvtrelation.RelationCallExp; @@ -49,141 +54,307 @@ import com.google.common.collect.Iterables; /*public*/ class RelationalTransformationToTracePackage { - protected final @NonNull QVTr2QVTc qvtr2qvtc; + public class Relation2TraceClass + { + protected final @NonNull Relation relation; + protected final @Nullable RelationCallExp invocation; + protected final org.eclipse.ocl.pivot.@NonNull Class traceClass; + protected final @NonNull Map<@NonNull String, @NonNull Property> name2property = new HashMap<>(); - public RelationalTransformationToTracePackage(@NonNull QVTr2QVTc qvtr2qvtc) { - this.qvtr2qvtc = qvtr2qvtc; - } + protected Relation2TraceClass(@NonNull Relation relation) { + this.relation = relation; + this.invocation = null; + this.traceClass = ClassUtil.nonNullState(PivotFactory.eINSTANCE.createClass()); + String name = "T" + relation.getName(); + traceClass.setName(getUniqueTraceClassName(this, name)); + qvtr2qvtc.putRelationTrace(relation, traceClass); + } - private void createTraceProperty(@Nullable Domain rDomain, org.eclipse.ocl.pivot.@NonNull Class rc, @NonNull TypedElement tv, boolean manyTraces) { - String vn = ClassUtil.nonNullState(tv.getName()); - Type c = ClassUtil.nonNullState(tv.getType()); - qvtr2qvtc.whenTraceProperty(rDomain, rc, vn, c, tv.isIsRequired(), manyTraces); - } + protected Relation2TraceClass(@NonNull RelationCallExp invocation, @NonNull String separator) throws CompilerChainException { + this.relation = QVTrelationUtil.getReferredRelation(invocation); + this.invocation = invocation; + this.traceClass = ClassUtil.nonNullState(PivotFactory.eINSTANCE.createClass()); + String invokedName = QVTrelationUtil.getContainingRelation(invocation).getName(); + String name = "T" + invokedName + separator + relation.getName(); + traceClass.setName(getUniqueTraceClassName(this, name)); + qvtr2qvtc.putInvocationTrace(invocation, traceClass); + Relation2TraceClass superRelation2TraceClass = getRelation2TraceClass(relation); + traceClass.getSuperClasses().add(superRelation2TraceClass.getTraceClass()); + name2property.putAll(superRelation2TraceClass.name2property); + } - private void createTraceProperty(@Nullable Domain rDomain, org.eclipse.ocl.pivot.@NonNull Class rc, @NonNull String name, @NonNull Type type, boolean isRequired) { - qvtr2qvtc.whenTraceProperty(rDomain, rc, name, type, isRequired, false); - } + private void createTraceProperty(@Nullable Domain rDomain, org.eclipse.ocl.pivot.@NonNull Class rc, @NonNull TypedElement tv, boolean manyTraces) throws CompilerChainException { + String vn = QVTrelationUtil.getName(tv); + Type c = QVTrelationUtil.getType(tv); + createTraceProperty(rDomain, rc, vn, c, tv.isIsRequired(), manyTraces); + } - public org.eclipse.ocl.pivot.@NonNull Package doRelationalTransformationToTracePackage(@NonNull RelationalTransformation rTransformation) { - org.eclipse.ocl.pivot.Package rPackage = rTransformation.getOwningPackage(); - org.eclipse.ocl.pivot.Package tracePackage = PivotFactory.eINSTANCE.createPackage(); - tracePackage.setName("P" + rTransformation.getName()); - tracePackage.setNsPrefix("P" + rTransformation.getName()); - StringBuilder s = new StringBuilder(); - getURI(rPackage, s); - tracePackage.setURI(s.toString() + "/" + rTransformation.getName()); - qvtr2qvtc.putTracePackage(rTransformation, tracePackage); - List<org.eclipse.ocl.pivot.@NonNull Class> ownedClasses = ClassUtil.nullFree(tracePackage.getOwnedClasses()); - for (@NonNull Rule rRule : ClassUtil.nullFree(rTransformation.getRule())) { - if (rRule instanceof Relation) { - ownedClasses.add(doRelationToTraceClass((Relation)rRule)); + private void createTraceProperty(@Nullable Domain rDomain, org.eclipse.ocl.pivot.@NonNull Class rc, @NonNull String name, @NonNull Type type, boolean isRequired, boolean manyTraces) throws CompilerChainException { + Property traceProperty = name2property.get(name); + if (traceProperty != null) { + if ((type != traceProperty.getType()) || isRequired != traceProperty.isIsRequired()) { + throw new CompilerChainException("Inconsistent redefined property '" + name + "' for " + relation); + } + } + else { + traceProperty = qvtr2qvtc.whenTraceProperty(rDomain, rc, name, type, isRequired, manyTraces); + name2property.put(name, traceProperty); } } - CompilerUtil.normalizeNameables(ownedClasses); - return tracePackage; - } - private org.eclipse.ocl.pivot.@NonNull Class doRelationToTraceClass(@NonNull Relation rRelation) { - @SuppressWarnings("null")org.eclipse.ocl.pivot.@NonNull Class traceClass = PivotFactory.eINSTANCE.createClass(); - qvtr2qvtc.putRelationTrace(rRelation, traceClass); - traceClass.setName("T" + rRelation.getName()); - for (@NonNull Variable rVariable : VariablesAnalysis.getMiddleDomainVariables(rRelation)) { - createTraceProperty(null, traceClass, rVariable, false); + /** + * Returns true if there are many subtemplate matches. If manyTraces is set there may be many trace class instances referencing the same objects + * and so the implicit opposites must be Bags. Only very simple patterns with pedantically 1:1 relationships can avoid the Bags. + * @throws CompilerChainException + */ + private boolean doSubTemplateToTraceClassProps(@NonNull Domain rDomain, @NonNull TemplateExp te, org.eclipse.ocl.pivot.@NonNull Class rc, boolean manyTraces) throws CompilerChainException { + Variable tv = QVTrelationUtil.getBindsTo(te); + if (te instanceof CollectionTemplateExp) { + CollectionTemplateExp cte = (CollectionTemplateExp) te; + Variable collectionVariable = QVTrelationUtil.getBindsTo(cte); + CollectionType collectionType = (CollectionType)QVTrelationUtil.getType(collectionVariable); + Type elementType = QVTrelationUtil.getElementType(collectionType); + int argIndex = 0; + for (@NonNull OCLExpression m : QVTrelationUtil.getOwnedMembers(cte)) { + if (m instanceof TemplateExp) { + if (doSubTemplateToTraceClassProps(rDomain, (TemplateExp)m, rc, manyTraces)) { + // manyTraces = true; + } + } + else if (!(m instanceof VariableExp)) { + createTraceProperty(rDomain, rc, collectionVariable.getName() + "_" + argIndex, elementType, collectionType.isIsNullFree(), false); + } + argIndex++; + } + // Variable rv = cte.getRest(); + // if (rv != null) { + // createTraceProperty(rDomain, rc, rv, isMany); + // } + createTraceProperty(rDomain, rc, tv, manyTraces); // ?? not required for CollectionTemplateExp's + } + else if (te instanceof ObjectTemplateExp) { + ObjectTemplateExp ote = (ObjectTemplateExp) te; + for (@NonNull PropertyTemplateItem pt : QVTrelationUtil.getOwnedParts(ote)) { + Property referredProperty = QVTrelationUtil.getReferredProperty(pt); + if (referredProperty.isIsMany()) { + manyTraces = true; + } + OCLExpression value = QVTrelationUtil.getOwnedValue(pt); + if (value instanceof TemplateExp) { + Property oppositeProperty = referredProperty.getOpposite(); + boolean nestedManyTraces = manyTraces; + if ((oppositeProperty != null) && oppositeProperty.isIsMany()) { + nestedManyTraces = true; + } + if (doSubTemplateToTraceClassProps(rDomain, (TemplateExp)value, rc, nestedManyTraces)) { + // manyTraces = true; + } + } + } + createTraceProperty(rDomain, rc, tv, manyTraces); // ?? not required for CollectionTemplateExp's + } + return manyTraces; + } + + public org.eclipse.ocl.pivot.@NonNull Class getTraceClass() { + return traceClass; } - // - // Determine whether a navigation from the trace to an unambiguous ledft/right object can ever be possible. - // - boolean manyTraces = hasManyRootMatches(rRelation) || hasCollectionMemberMatches(rRelation) || hasMultiObjectMatches(rRelation); - if (!manyTraces) { - for (@NonNull Variable rVariable : ClassUtil.nullFree(rRelation.getVariable())) { - if (hasManyVariableMatches(rRelation, rVariable)) { - manyTraces = true; - break; + + private boolean hasCollectionMemberMatches(@NonNull Relation rRelation) { + for (EObject eObject : new TreeIterable(rRelation, true)) { + if (eObject instanceof CollectionTemplateExp) { + List<OCLExpression> members = ((CollectionTemplateExp)eObject).getMember(); + if (members.size() > 0) { + return true; + } } } + return false; } - for (@NonNull Domain rDomain : ClassUtil.nullFree(rRelation.getDomain())) { - for (@NonNull DomainPattern rDomainPattern : ClassUtil.nullFree(((RelationDomain)rDomain).getPattern())) { - TemplateExp rTemplateExp = ClassUtil.nonNullState(rDomainPattern.getTemplateExpression()); - doSubTemplateToTraceClassProps(rDomain, rTemplateExp, traceClass, manyTraces); + + /** + * Return true if there may be more than one trace instance for a given root variable. + */ + private boolean hasManyRootMatches(@NonNull Relation rRelation) { + // + // Only a single root variable in each of just two domains gurantees just one trace per root variable. + // + List<@NonNull Domain> rDomains = QVTrelationUtil.Internal.getOwnedDomainsList(rRelation); + if (rDomains.size() > 2) { + return true; } + else { + for (@NonNull Domain rDomain : rDomains) { + List<Variable> rootVariables = ((RelationDomain)rDomain).getRootVariable(); + if (rootVariables.size() > 1) { + return true; + } + } + } + return false; } - Pattern rWhenPattern = rRelation.getWhen(); - if (rWhenPattern != null) { - for (Predicate rWhenPredicate : ClassUtil.nullFree(rWhenPattern.getPredicate())) { - OCLExpression rConditionExpression = ClassUtil.nonNullState(rWhenPredicate.getConditionExpression()); - if (rConditionExpression instanceof RelationCallExp) { - RelationCallExp rInvocation = (RelationCallExp)rConditionExpression; - List<@NonNull OCLExpression> rArguments = ClassUtil.nullFree(rInvocation.getArgument()); - for (int i = 0; i < rArguments.size(); i++) { - OCLExpression rArgument = rArguments.get(i); - if (rArgument instanceof VariableExp) { - VariableDeclaration rVariable = ((VariableExp)rArgument).getReferredVariable(); - assert rVariable != null; - RelationDomain rDomain = QVTrelationUtil.getRelationCallExpArgumentDomain(rInvocation, i); - createTraceProperty(rDomain, traceClass, rVariable, manyTraces); - // createTraceProperty(rDomain, rVariable.getType(), rVariable, isMany); // ?? not required for CollectionTemplateExp's + + private boolean hasManyVariableMatches(@NonNull Relation rRelation, @NonNull Variable rVariable) { + for (@NonNull Domain rDomain : QVTrelationUtil.getOwnedDomains(rRelation)) { + Iterable<@NonNull Variable> bindsTo = QVTr2QVTcUtil.getRelationDomainBindsTo((RelationDomain) rDomain); + if (Iterables.contains(bindsTo, rVariable)) { + return false; + } + } + for (EObject eObject : new TreeIterable(rRelation, true)) { + if (eObject instanceof VariableExp) { + VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable(); + if (referredVariable == rVariable) { + EObject eContainer = eObject.eContainer(); + if (eContainer instanceof OperationCallExp) { + OperationCallExp operationCallExp = (OperationCallExp)eContainer; + Operation referredOperation = operationCallExp.getReferredOperation(); + assert referredOperation != null; + if (operationCallExp.getOwnedArguments().equals(Collections.singletonList(eObject)) && "includes".equals(referredOperation.getName())) { // FIXME stronger test + return true; + } } + // FIXME more cases } } } + return false; } - CompilerUtil.normalizeNameables(ClassUtil.nullFree(traceClass.getOwnedProperties())); - return traceClass; - } - /** - * Returns true if there are many subtemplate matches. If manyTraces is set there may be many trace class instances referencing the same objects - * and so the implicit opposites must be Bags. Only very simple patterns with pedantically 1:1 relationships can avoid the Bags. - */ - private boolean doSubTemplateToTraceClassProps(@NonNull Domain rDomain, @NonNull TemplateExp te, org.eclipse.ocl.pivot.@NonNull Class rc, boolean manyTraces) { - Variable tv = ClassUtil.nonNullState(te.getBindsTo()); - if (te instanceof CollectionTemplateExp) { - CollectionTemplateExp cte = (CollectionTemplateExp) te; - Variable collectionVariable = cte.getBindsTo(); - CollectionType collectionType = (CollectionType)collectionVariable.getType(); - Type elementType = ClassUtil.nonNullState(collectionType.getElementType()); - int argIndex = 0; - for (@NonNull OCLExpression m : ClassUtil.nullFree(cte.getMember())) { - if (m instanceof TemplateExp) { - if (doSubTemplateToTraceClassProps(rDomain, (TemplateExp)m, rc, manyTraces)) { - // manyTraces = true; + private boolean hasMultiObjectMatches(@NonNull Relation rRelation) { + for (EObject eObject : new TreeIterable(rRelation, true)) { + if (eObject instanceof PropertyTemplateItem) { + Property referredProperty = ((PropertyTemplateItem)eObject).getReferredProperty(); + if (referredProperty.isIsMany()) { + return true; } } - else if (!(m instanceof VariableExp)) { - createTraceProperty(rDomain, rc, collectionVariable.getName() + "_" + argIndex, elementType, collectionType.isIsNullFree()); - } - argIndex++; } - // Variable rv = cte.getRest(); - // if (rv != null) { - // createTraceProperty(rDomain, rc, rv, isMany); - // } - createTraceProperty(rDomain, rc, tv, manyTraces); // ?? not required for CollectionTemplateExp's + return false; } - else if (te instanceof ObjectTemplateExp) { - ObjectTemplateExp ote = (ObjectTemplateExp) te; - for (@NonNull PropertyTemplateItem pt : ClassUtil.nullFree(ote.getPart())) { - Property referredProperty = pt.getReferredProperty(); - if (referredProperty.isIsMany()) { - manyTraces = true; - } - OCLExpression value = ClassUtil.nonNullState(pt.getValue()); - if (value instanceof TemplateExp) { - Property oppositeProperty = referredProperty.getOpposite(); - boolean nestedManyTraces = manyTraces; - if ((oppositeProperty != null) && oppositeProperty.isIsMany()) { - nestedManyTraces = true; + + @Override + public String toString() { + return relation.toString(); + } + + public org.eclipse.ocl.pivot.@NonNull Class transform() throws CompilerChainException { + Relation overriddenRelation = QVTrelationUtil.basicGetOverrides(relation); + if (overriddenRelation != null) { + Relation2TraceClass overriddenRelation2TraceClass = getRelation2TraceClass(overriddenRelation); + name2property.putAll(overriddenRelation2TraceClass.name2property); + traceClass.getSuperClasses().add(overriddenRelation2TraceClass.traceClass); + } + + for (@NonNull Variable rVariable : VariablesAnalysis.getMiddleDomainVariables(relation)) { + createTraceProperty(null, traceClass, rVariable, false); + } + if (testableRelations.contains(relation) ) { + Type booleanType = qvtr2qvtc.getStandardLibrary().getBooleanType(); + createTraceProperty(null, traceClass, QVTrNameGenerator.TRACECLASS_SUCCESS_PROPERTY_NAME, booleanType, false, false); + } + // + // Determine whether a navigation from the trace to an unambiguous left/right object can ever be possible. + // + boolean manyTraces = hasManyRootMatches(relation) || hasCollectionMemberMatches(relation) || hasMultiObjectMatches(relation); + if (!manyTraces) { + for (@NonNull Variable rVariable : QVTrelationUtil.getOwnedVariables(relation)) { + if (hasManyVariableMatches(relation, rVariable)) { + manyTraces = true; + break; } - if (doSubTemplateToTraceClassProps(rDomain, (TemplateExp)value, rc, nestedManyTraces)) { - // manyTraces = true; + } + } + for (@NonNull RelationDomain rDomain : QVTrelationUtil.getOwnedDomains(relation)) { + for (@NonNull DomainPattern rDomainPattern : QVTrelationUtil.getOwnedPatterns(rDomain)) { + TemplateExp rTemplateExp = QVTrelationUtil.getOwnedTemplateExpression(rDomainPattern); + doSubTemplateToTraceClassProps(rDomain, rTemplateExp, traceClass, manyTraces); + } + } + Pattern rWhenPattern = relation.getWhen(); + if (rWhenPattern != null) { + for (Predicate rWhenPredicate : QVTrelationUtil.getOwnedPredicates(rWhenPattern)) { + OCLExpression rConditionExpression = QVTrelationUtil.getConditionExpression(rWhenPredicate); + if (rConditionExpression instanceof RelationCallExp) { + RelationCallExp rInvocation = (RelationCallExp)rConditionExpression; + List<@NonNull OCLExpression> rArguments = QVTrelationUtil.Internal.getOwnedArgumentsList(rInvocation); + for (int i = 0; i < rArguments.size(); i++) { + OCLExpression rArgument = rArguments.get(i); + if (rArgument instanceof VariableExp) { + VariableDeclaration rVariable = ((VariableExp)rArgument).getReferredVariable(); + assert rVariable != null; + RelationDomain rDomain = QVTrelationUtil.getRelationCallExpArgumentDomain(rInvocation, i); + createTraceProperty(rDomain, traceClass, rVariable, manyTraces); + // createTraceProperty(rDomain, rVariable.getType(), rVariable, isMany); // ?? not required for CollectionTemplateExp's + } + } } } } - createTraceProperty(rDomain, rc, tv, manyTraces); // ?? not required for CollectionTemplateExp's + CompilerUtil.normalizeNameables(ClassUtil.nullFree(traceClass.getOwnedProperties())); + return traceClass; + } + } + + protected final @NonNull QVTr2QVTc qvtr2qvtc; + protected final @NonNull RelationalTransformation rTransformation; + private @NonNull Set<@NonNull Relation> testableRelations = new HashSet<>(); + + /** + * Name to corresponding trace class + */ + protected final @NonNull Map<@NonNull String, @NonNull Relation2TraceClass> name2relation2traceClass = new HashMap<>(); + + /** + * Map of relation to trace class. The trace class is set null at the start of conversion enabling cycles to be ddetected. + */ + protected final @NonNull Map<@NonNull Relation, @Nullable Relation2TraceClass> relation2relation2traceClass = new HashMap<>(); + + /** + * Map of invocation to trace class. The trace class is set null at the start of conversion enabling cycles to be ddetected. + */ + protected final @NonNull Map<@NonNull RelationCallExp, @Nullable Relation2TraceClass> invocation2relation2traceClass = new HashMap<>(); + + public RelationalTransformationToTracePackage(@NonNull QVTr2QVTc qvtr2qvtc, @NonNull RelationalTransformation rTransformation) { + this.qvtr2qvtc = qvtr2qvtc; + this.rTransformation = rTransformation; + for (@NonNull EObject eObject : new TreeIterable(rTransformation, false)) { + if ((eObject instanceof RelationCallExp) && !(eObject.eContainer() instanceof Predicate)) { + testableRelations.add(QVTrelationUtil.getReferredRelation((RelationCallExp)eObject)); + } + } + } + + protected @NonNull Relation2TraceClass getInvocation2TraceClass(@NonNull RelationCallExp rInvocation, @NonNull String separator) throws CompilerChainException { + Relation2TraceClass relation2traceClass = new Relation2TraceClass(rInvocation, separator); + Relation2TraceClass oldRelation2traceClass = invocation2relation2traceClass.put(rInvocation, relation2traceClass); + assert oldRelation2traceClass == null; + relation2traceClass.transform(); + return relation2traceClass; + } + + protected @NonNull Relation2TraceClass getRelation2TraceClass(@NonNull Relation rRelation) throws CompilerChainException { + Relation2TraceClass relation2traceClass = relation2relation2traceClass.get(rRelation); + if (relation2traceClass == null) { + if (relation2relation2traceClass.containsKey(rRelation)) { + throw new CompilerChainException("Overrides cycle detected for " + rRelation); + } + relation2traceClass = new Relation2TraceClass(rRelation); + relation2relation2traceClass.put(rRelation, null); + relation2traceClass.transform(); + relation2relation2traceClass.put(rRelation, relation2traceClass); + } + return relation2traceClass; + } + + private @NonNull String getUniqueTraceClassName(@NonNull Relation2TraceClass relation2traceClass, @NonNull String name) { + String uniqueName = name; + int suffix = 0; + while (name2relation2traceClass.get(uniqueName) != null) { + uniqueName = name + ++suffix; } - return manyTraces; + name2relation2traceClass.put(uniqueName, relation2traceClass); + return uniqueName; } private String getURI(org.eclipse.ocl.pivot.Package rPackage, @NonNull StringBuilder s) { @@ -201,76 +372,47 @@ import com.google.common.collect.Iterables; return null; } - private boolean hasCollectionMemberMatches(@NonNull Relation rRelation) { - for (EObject eObject : new TreeIterable(rRelation, true)) { - if (eObject instanceof CollectionTemplateExp) { - List<OCLExpression> members = ((CollectionTemplateExp)eObject).getMember(); - if (members.size() > 0) { - return true; - } - } - } - return false; + @Override + public String toString() { + return rTransformation.toString(); } - /** - * Return true if there may be more than one trace instance for a given root variable. - */ - private boolean hasManyRootMatches(@NonNull Relation rRelation) { - // - // Only a single root variable in each of just two domains gurantees just one trace per root variable. - // - List<@NonNull Domain> rDomains = ClassUtil.nullFree(rRelation.getDomain()); - if (rDomains.size() > 2) { - return true; + public org.eclipse.ocl.pivot.@NonNull Package transform() throws CompilerChainException { + org.eclipse.ocl.pivot.Package rPackage = rTransformation.getOwningPackage(); + org.eclipse.ocl.pivot.Package tracePackage = PivotFactory.eINSTANCE.createPackage(); + tracePackage.setName("P" + rTransformation.getName()); + tracePackage.setNsPrefix("P" + rTransformation.getName()); + StringBuilder s = new StringBuilder(); + getURI(rPackage, s); + tracePackage.setURI(s.toString() + "/" + rTransformation.getName()); + qvtr2qvtc.putTracePackage(rTransformation, tracePackage); + for (@NonNull Relation rRelation : QVTrelationUtil.getOwnedRelations(rTransformation)) { + // if (rRelation.isIsTopLevel()) { + getRelation2TraceClass(rRelation); + // } } - else { - for (@NonNull Domain rDomain : rDomains) { - List<Variable> rootVariables = ((RelationDomain)rDomain).getRootVariable(); - if (rootVariables.size() > 1) { - return true; + for (@NonNull Relation rRelation : QVTrelationUtil.getOwnedRelations(rTransformation)) { + if (!rRelation.isIsTopLevel()) { + Iterable<@NonNull RelationCallExp> whenInvocations = qvtr2qvtc.getWhenRelationCallExpsForRelation(rRelation); + if (whenInvocations != null) { + for (@NonNull RelationCallExp rInvocation : whenInvocations) { + getInvocation2TraceClass(rInvocation, "_when_"); + } } - } - } - return false; - } - - private boolean hasManyVariableMatches(@NonNull Relation rRelation, @NonNull Variable rVariable) { - for (@NonNull Domain rDomain : ClassUtil.nullFree(rRelation.getDomain())) { - Iterable<@NonNull Variable> bindsTo = QVTr2QVTcUtil.getRelationDomainBindsTo((RelationDomain) rDomain); - if (Iterables.contains(bindsTo, rVariable)) { - return false; - } - } - for (EObject eObject : new TreeIterable(rRelation, true)) { - if (eObject instanceof VariableExp) { - VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable(); - if (referredVariable == rVariable) { - EObject eContainer = eObject.eContainer(); - if (eContainer instanceof OperationCallExp) { - OperationCallExp operationCallExp = (OperationCallExp)eContainer; - Operation referredOperation = operationCallExp.getReferredOperation(); - assert referredOperation != null; - if (operationCallExp.getOwnedArguments().equals(Collections.singletonList(eObject)) && "includes".equals(referredOperation.getName())) { // FIXME stronger test - return true; - } + Iterable<@NonNull RelationCallExp> whereInvocations = qvtr2qvtc.getWhereRelationCallExpsForRelation(rRelation); + if (whereInvocations != null) { + for (@NonNull RelationCallExp rInvocation : whereInvocations) { + getInvocation2TraceClass(rInvocation, "_where_"); } - // FIXME more cases } } } - return false; - } - - private boolean hasMultiObjectMatches(@NonNull Relation rRelation) { - for (EObject eObject : new TreeIterable(rRelation, true)) { - if (eObject instanceof PropertyTemplateItem) { - Property referredProperty = ((PropertyTemplateItem)eObject).getReferredProperty(); - if (referredProperty.isIsMany()) { - return true; - } - } + List<org.eclipse.ocl.pivot.@NonNull Class> traceClasses = new ArrayList<>(name2relation2traceClass.size()); + for (@NonNull Relation2TraceClass relation2TraceClass : name2relation2traceClass.values()) { + traceClasses.add(relation2TraceClass.getTraceClass()); } - return false; + CompilerUtil.normalizeNameables(traceClasses); + tracePackage.getOwnedClasses().addAll(traceClasses); + return tracePackage; } } |