/*******************************************************************************
* Copyright (c) 2012, 2015 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.ocl.xtext.completeocl.cs2as;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Class;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.Import;
import org.eclipse.ocl.pivot.Iteration;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.PivotPackage;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.internal.scoping.EnvironmentView;
import org.eclipse.ocl.pivot.internal.scoping.ScopeFilter;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.xtext.base.cs2as.CS2AS;
import org.eclipse.ocl.xtext.base.cs2as.CS2ASConversion;
import org.eclipse.ocl.xtext.base.cs2as.Continuation;
import org.eclipse.ocl.xtext.basecs.ConstraintCS;
import org.eclipse.ocl.xtext.basecs.ParameterCS;
import org.eclipse.ocl.xtext.basecs.PathNameCS;
import org.eclipse.ocl.xtext.completeoclcs.ClassifierContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.CompleteOCLDocumentCS;
import org.eclipse.ocl.xtext.completeoclcs.ContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.DefCS;
import org.eclipse.ocl.xtext.completeoclcs.DefOperationCS;
import org.eclipse.ocl.xtext.completeoclcs.DefPropertyCS;
import org.eclipse.ocl.xtext.completeoclcs.OperationContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.PackageDeclarationCS;
import org.eclipse.ocl.xtext.completeoclcs.PropertyContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.util.AbstractCompleteOCLCSContainmentVisitor;
import org.eclipse.ocl.xtext.essentialoclcs.ExpSpecificationCS;
public class CompleteOCLCSContainmentVisitor extends AbstractCompleteOCLCSContainmentVisitor
{
public class OperationDeclScopeFilter implements ScopeFilter
{
protected final @Nullable Type sourceType;
private final @NonNull List<ParameterCS> csParameters;
public OperationDeclScopeFilter(@Nullable Type sourceType, @NonNull List<ParameterCS> csParameters) {
this.sourceType = sourceType != null ? PivotUtilInternal.getType(sourceType) : null; // FIXME redundant
this.csParameters = csParameters;
}
@Override
public boolean matches(@NonNull EnvironmentView environmentView, @NonNull Object object) {
if (object instanceof Iteration) {
return false;
}
if (object instanceof Operation) {
Operation candidateOperation = (Operation)object;
List<Parameter> candidateParameters = candidateOperation.getOwnedParameters();
int iMax = csParameters.size();
if (iMax != candidateParameters.size()) {
return false;
}
return true;
}
else {
return false;
}
}
}
public CompleteOCLCSContainmentVisitor(@NonNull CS2ASConversion context) {
super(context);
}
/* let classifierContextDecls = contextDecls->selectByKind(ClassifierContextDeclCS) in
let classifierInvariants = classifierContextDecls.ownedInvariants in
let defOperations = classifierContextDecls.ownedDefinitions->selectByKind(DefOperationCS) in
let defProperties = classifierContextDecls.ownedDefinitions->selectByKind(DefPropertyCS) in
let operationContextDecls = contextDecls->selectByKind(OperationContextDeclCS) in
let propertyContextDecls = contextDecls->selectByKind(PropertyContextDeclCS) in
let propertyInvariants = propertyContextDecls.ownedDerivedInvariants in
ocl::Class {
name = modelClass.name,
ownedInvariants = classifierInvariants.ast()->union(propertyInvariants.ast()),
ownedOperations = operationContextDecls->collect(o | contextOperation(o))->union(defOperations.ast())->sortedBy(name),
ownedProperties = propertyContextDecls->collect(p | contextProperty(p))->union(defProperties.ast())->sortedBy(name)
} */
private org.eclipse.ocl.pivot.@NonNull Class contextClass(org.eclipse.ocl.pivot.@NonNull Class modelClass,
@NonNull List<ContextDeclCS> contextDecls) {
List<ConstraintCS> allInvariants = new ArrayList<ConstraintCS>();
List<ClassifierContextDeclCS> classifierContextDecls = new ArrayList<ClassifierContextDeclCS>();
List<OperationContextDeclCS> operationContextDecls = new ArrayList<OperationContextDeclCS>();
List<PropertyContextDeclCS> propertyContextDecls = new ArrayList<PropertyContextDeclCS>();
List<DefOperationCS> defOperations = new ArrayList<DefOperationCS>();
List<DefPropertyCS> defProperties = new ArrayList<DefPropertyCS>();
for (ContextDeclCS contextDecl : contextDecls) {
if (contextDecl instanceof ClassifierContextDeclCS) {
ClassifierContextDeclCS classifierContextDecl = (ClassifierContextDeclCS)contextDecl;
classifierContextDecls.add(classifierContextDecl);
allInvariants.addAll(classifierContextDecl.getOwnedInvariants());
for (DefCS csDef : classifierContextDecl.getOwnedDefinitions()) {
if (csDef instanceof DefOperationCS) {
defOperations.add((DefOperationCS) csDef);
}
else if (csDef instanceof DefPropertyCS) {
defProperties.add((DefPropertyCS) csDef);
}
}
}
else if (contextDecl instanceof OperationContextDeclCS) {
operationContextDecls.add((OperationContextDeclCS) contextDecl);
}
else if (contextDecl instanceof PropertyContextDeclCS) {
PropertyContextDeclCS propertyContextDecl = (PropertyContextDeclCS) contextDecl;
propertyContextDecls.add(propertyContextDecl);
allInvariants.addAll(propertyContextDecl.getOwnedDerivedInvariants());
}
}
List<Operation> contextOperations = new ArrayList<Operation>();
for (OperationContextDeclCS operationContextDecl : operationContextDecls) {
if (operationContextDecl != null) {
Operation contextOperation = contextOperation(operationContextDecl);
contextOperations.add(contextOperation);
}
}
for (DefOperationCS defOperation : defOperations) {
Operation contextOperation = PivotUtil.getPivot(Operation.class, defOperation);
if (contextOperation != null) {
contextOperations.add(contextOperation);
}
}
Collections.sort(contextOperations, NameUtil.NAMEABLE_COMPARATOR);
List<Property> contextProperties = new ArrayList<Property>();
for (PropertyContextDeclCS propertyContextDecl : propertyContextDecls) {
if (propertyContextDecl != null) {
Property contextProperty = contextProperty(propertyContextDecl);
contextProperties.add(contextProperty);
}
}
for (DefPropertyCS defProperty : defProperties) {
Property contextProperty = PivotUtil.getPivot(Property.class, defProperty);
if (contextProperty != null) {
contextProperties.add(contextProperty);
}
}
Collections.sort(contextProperties, NameUtil.NAMEABLE_COMPARATOR);
ClassifierContextDeclCS csElement = classifierContextDecls.size() > 0 ? classifierContextDecls.get(0) : null;
org.eclipse.ocl.pivot.Class contextClass = context.refreshModelElement(org.eclipse.ocl.pivot.Class.class, PivotPackage.Literals.CLASS, csElement);
contextClass.setName(modelClass.getName());
context.refreshPivotList(Constraint.class, contextClass.getOwnedInvariants(), allInvariants);
context.refreshList(contextClass.getOwnedOperations(), contextOperations);
context.refreshList(contextClass.getOwnedProperties(), contextProperties);
context.refreshComments(contextClass, csElement);
for (@SuppressWarnings("null")@NonNull ContextDeclCS contextDecl : contextDecls) {
if (contextDecl instanceof ClassifierContextDeclCS) {
context.installPivotUsage(contextDecl, contextClass);
}
}
return contextClass;
}
/* let modelOperation = operationContext.referredOperation in
ocl::Operation {
name = modelOperation.name,
type = modelOperation.type,
isRequired = modelOperation.isRequired,
ownedParameter = modelOperation.ownedParameter,
isStatic = modelOperation.isStatic,
bodyExpression = if operationContext.ownedBodies->notEmpty() then operationContext.ownedBodies->first().ast() else null endif,
postcondition = operationContext.ownedPostconditions.ast(),
precondition = operationContext.ownedPreconditions.ast()
} */
private @NonNull Operation contextOperation(@NonNull OperationContextDeclCS operationContextDecl) {
Operation contextOperation = context.refreshModelElement(Operation.class, PivotPackage.Literals.OPERATION, operationContextDecl);
Operation modelOperation = operationContextDecl.getReferredOperation();
if (modelOperation != null) {
context.refreshName(contextOperation, ClassUtil.nonNullModel(modelOperation.getName()));
context.setType(contextOperation, modelOperation.getType(), modelOperation.isIsRequired());
List<ExpSpecificationCS> ownedBodies = operationContextDecl.getOwnedBodies();
ExpSpecificationCS ownedBody = ownedBodies.size() > 0 ? ownedBodies.get(0) : null;
LanguageExpression languageExpression = ownedBody != null ? PivotUtil.getPivot(LanguageExpression.class, ownedBody) : null;
contextOperation.setBodyExpression(languageExpression);
context.refreshPivotList(Parameter.class, contextOperation.getOwnedParameters(), operationContextDecl.getOwnedParameters());
context.refreshPivotList(Constraint.class, contextOperation.getOwnedPreconditions(), operationContextDecl.getOwnedPreconditions());
context.refreshPivotList(Constraint.class, contextOperation.getOwnedPostconditions(), operationContextDecl.getOwnedPostconditions());
}
context.refreshComments(contextOperation, operationContextDecl);
return contextOperation;
}
/* let packageInvariants = packageDecls.ownedInvariants in
let allContextDecls = contextDecls->union(packageDecls.ownedContexts)->asSet() in
let modelClasses = allContextDecls.referredClass()->asSet() in
ocl::Package {
name = modelPackage.name,
nsPrefix = modelPackage.nsPrefix,
URI = modelPackage.URI,
-- ownedInvariants = packageInvariants.ast(),
ownedClasses = modelClasses->sortedBy(name)->collect(c | contextClass(c, allContextDecls->select(cd | cd.referredClass() = c)))
} */
private org.eclipse.ocl.pivot.@NonNull Package contextPackage(org.eclipse.ocl.pivot.@NonNull Package modelPackage,
@NonNull List<PackageDeclarationCS> packageDecls, @NonNull List<ContextDeclCS> contextDecls) {
List<ConstraintCS> packageInvariants = new ArrayList<ConstraintCS>();
List<ContextDeclCS> allContextDecls = new ArrayList<ContextDeclCS>(contextDecls);
for (PackageDeclarationCS packageDecl : packageDecls) {
packageInvariants.addAll(packageDecl.getOwnedInvariants());
allContextDecls.addAll(packageDecl.getOwnedContexts());
}
Set<org.eclipse.ocl.pivot.Class> modelClasses = new HashSet<org.eclipse.ocl.pivot.Class>();
for (ContextDeclCS contextDecl : allContextDecls) {
Class modelClass = getReferredClass(contextDecl);
if (modelClass != null) {
modelClasses.add(modelClass);
}
}
List<org.eclipse.ocl.pivot.Class> sortedModelClasses = new ArrayList<org.eclipse.ocl.pivot.Class>(modelClasses);
Collections.sort(sortedModelClasses, NameUtil.NAMEABLE_COMPARATOR);
List<org.eclipse.ocl.pivot.Class> contextClasses = new ArrayList<org.eclipse.ocl.pivot.Class>();
for (org.eclipse.ocl.pivot.Class modelClass : sortedModelClasses) {
if (modelClass != null) {
List<ContextDeclCS> selectedContexts = new ArrayList<ContextDeclCS>();
for (ContextDeclCS csContext : allContextDecls) {
org.eclipse.ocl.pivot.Class asClass = getReferredClass(csContext);
if (modelClass == asClass) {
selectedContexts.add(csContext);
}
}
org.eclipse.ocl.pivot.Class contextClass = contextClass(modelClass, selectedContexts);
contextClasses.add(contextClass);
}
}
PackageDeclarationCS csElement = packageDecls.size() > 0 ? packageDecls.get(0) : null;
org.eclipse.ocl.pivot.Package contextPackage = context.refreshModelElement(org.eclipse.ocl.pivot.Package.class, PivotPackage.Literals.PACKAGE, csElement);
contextPackage.setName(modelPackage.getName());
contextPackage.setURI(modelPackage.getURI());
context.refreshList(contextPackage.getOwnedClasses(), contextClasses);
context.refreshComments(contextPackage, csElement);
for (int i = 1; i < packageDecls.size(); i++) {
csElement = packageDecls.get(i);
if (csElement != null) {
context.installPivotUsage(csElement, contextPackage);
}
}
return contextPackage;
}
/* let modelProperty = propertyContext.referredProperty in
ocl::Property {
name = modelProperty.name,
type = modelProperty.type,
isRequired = modelProperty.isRequired,
isStatic = modelProperty.isStatic,
defaultExpression = if propertyContext.ownedDefaultExpressions->notEmpty() then propertyContext.ownedDefaultExpressions->first().ast() else null endif
} */
private @NonNull Property contextProperty(@NonNull PropertyContextDeclCS propertyContextDecl) {
Property contextProperty = context.refreshModelElement(Property.class, PivotPackage.Literals.PROPERTY, propertyContextDecl);
Property modelProperty = propertyContextDecl.getReferredProperty();
if (modelProperty != null) {
context.refreshName(contextProperty, ClassUtil.nonNullModel(modelProperty.getName()));
context.setType(contextProperty, modelProperty.getType(), modelProperty.isIsRequired());
List<ExpSpecificationCS> ownedDefaultExpressions = propertyContextDecl.getOwnedDefaultExpressions();
ExpSpecificationCS ownedDefaultExpression = ownedDefaultExpressions.size() > 0 ? ownedDefaultExpressions.get(0) : null;
LanguageExpression languageExpression = ownedDefaultExpression != null ? PivotUtil.getPivot(LanguageExpression.class, ownedDefaultExpression) : null;
contextProperty.setOwnedExpression(languageExpression);
}
context.refreshComments(contextProperty, propertyContextDecl);
return contextProperty;
}
private org.eclipse.ocl.pivot.@Nullable Class getReferredClass(ContextDeclCS csContext) {
if (csContext instanceof ClassifierContextDeclCS) {
return ((ClassifierContextDeclCS)csContext).getReferredClass();
}
else if (csContext instanceof OperationContextDeclCS) {
Operation modelOperation = ((OperationContextDeclCS)csContext).getReferredOperation();
return modelOperation != null ? modelOperation.getOwningClass() : null;
}
else if (csContext instanceof PropertyContextDeclCS) {
Property modelProperty = ((PropertyContextDeclCS)csContext).getReferredProperty();
return modelProperty != null ? modelProperty.getOwningClass() : null;
}
return null;
}
private org.eclipse.ocl.pivot.@Nullable Package getReferredPackage(@NonNull ContextDeclCS csContext) {
org.eclipse.ocl.pivot.Class modelClass = getReferredClass(csContext);
return modelClass != null ? modelClass.getOwningPackage() : null;
}
@Override
public Continuation<?> visitClassifierContextDeclCS(@NonNull ClassifierContextDeclCS csElement) {
return null;
}
// let modelPackages = ownedPackages.referredPackage->asSet()->union(ownedContexts.referredPackage()) in
// ocl::Model {
// name = name,
// imports = ownedIncludes.ast(),
// ownedPackages = modelPackages->sortedBy(name)->collect(p | contextPackage(p, ownedPackages->select(referredPackage = p), ownedContexts->select(referredPackage() = p)))
// }
@Override
public Continuation<?> visitCompleteOCLDocumentCS(@NonNull CompleteOCLDocumentCS csElement) {
Set<org.eclipse.ocl.pivot.Package> modelPackages = new HashSet<org.eclipse.ocl.pivot.Package>();
List<PackageDeclarationCS> ownedPackages = csElement.getOwnedPackages();
for (PackageDeclarationCS csPackage : ownedPackages) {
org.eclipse.ocl.pivot.Package modelPackage = csPackage.getReferredPackage();
if (modelPackage != null) {
modelPackages.add(modelPackage);
}
}
List<ContextDeclCS> ownedContexts = csElement.getOwnedContexts();
for (ContextDeclCS csContext : ownedContexts) {
if (csContext != null) {
org.eclipse.ocl.pivot.Package modelPackage = getReferredPackage(csContext);
if (modelPackage != null) {
modelPackages.add(modelPackage);
}
}
}
List<org.eclipse.ocl.pivot.Package> sortedModelPackages = new ArrayList<org.eclipse.ocl.pivot.Package>(modelPackages);
Collections.sort(sortedModelPackages, NameUtil.NAMEABLE_COMPARATOR);
List<org.eclipse.ocl.pivot.Package> contextPackages = new ArrayList<org.eclipse.ocl.pivot.Package>();
for (org.eclipse.ocl.pivot.Package modelPackage : sortedModelPackages) {
if (modelPackage != null) {
List<PackageDeclarationCS> selectedPackageDecls = new ArrayList<PackageDeclarationCS>();
for (PackageDeclarationCS csPackage : ownedPackages) {
org.eclipse.ocl.pivot.Package asPackage = csPackage.getReferredPackage();
if (modelPackage == asPackage) {
selectedPackageDecls.add(csPackage);
}
}
List<ContextDeclCS> selectedContexts = new ArrayList<ContextDeclCS>();
for (ContextDeclCS csContext : ownedContexts) {
if (csContext != null) {
org.eclipse.ocl.pivot.Package asPackage = getReferredPackage(csContext);
if (modelPackage == asPackage) {
selectedContexts.add(csContext);
}
}
}
org.eclipse.ocl.pivot.Package contextPackage = contextPackage(modelPackage, selectedPackageDecls, selectedContexts);
contextPackages.add(contextPackage);
}
}
@NonNull Model contextRoot = refreshRoot(Model.class, PivotPackage.Literals.MODEL, csElement);
context.refreshPivotList(Import.class, contextRoot.getOwnedImports(), csElement.getOwnedImports());
context.refreshList(contextRoot.getOwnedPackages(), contextPackages);
return null;
}
@Override
public Continuation<?> visitDefOperationCS(@NonNull DefOperationCS csElement) {
@NonNull Operation contextOperation = refreshNamedElement(Operation.class, PivotPackage.Literals.OPERATION, csElement);
context.refreshPivotList(Parameter.class, contextOperation.getOwnedParameters(), csElement.getOwnedParameters());
ExpressionInOCL pivotSpecification = PivotUtil.getPivot(ExpressionInOCL.class, csElement.getOwnedSpecification());
contextOperation.setBodyExpression(pivotSpecification);
return null;
}
@Override
public Continuation<?> visitDefPropertyCS(@NonNull DefPropertyCS csElement) {
@NonNull Property contextProperty = refreshNamedElement(Property.class, PivotPackage.Literals.PROPERTY, csElement);
contextProperty.setIsDerived(true);
contextProperty.setIsReadOnly(true);
contextProperty.setIsTransient(true);
contextProperty.setIsVolatile(true);
contextProperty.setIsResolveProxies(false);
ExpressionInOCL pivotSpecification = PivotUtil.getPivot(ExpressionInOCL.class, csElement.getOwnedSpecification());
contextProperty.setOwnedExpression(pivotSpecification);
return null;
}
@Override
public Continuation<?> visitOperationContextDeclCS(@NonNull OperationContextDeclCS csElement) {
List<ParameterCS> csParameters = csElement.getOwnedParameters();
assert csParameters != null;
PathNameCS pathName = csElement.getOwnedPathName();
assert pathName != null;
CS2AS.setElementType(pathName, PivotPackage.Literals.OPERATION, csElement, new OperationDeclScopeFilter(null, csParameters));
return null;
}
@Override
public Continuation<?> visitPackageDeclarationCS(@NonNull PackageDeclarationCS csElement) {
return null;
}
@Override
public Continuation<?> visitPropertyContextDeclCS(@NonNull PropertyContextDeclCS csElement) {
return null;
}
}