blob: 2afa88c06eb31b27e1b68947f7648ee6d332ba2c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 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
* E.D.Willink (Obeo) - Bug 416287 - tuple-valued constraints
*******************************************************************************/
package org.eclipse.ocl.xtext.completeocl.as2cs;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CompletePackage;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.Namespace;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Package;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.internal.prettyprint.PrettyPrintOptions;
import org.eclipse.ocl.pivot.internal.prettyprint.PrettyPrinter;
import org.eclipse.ocl.pivot.utilities.PivotConstants;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.xtext.base.as2cs.AS2CSConversion;
import org.eclipse.ocl.xtext.base.as2cs.AliasAnalysis;
import org.eclipse.ocl.xtext.base.utilities.BaseCSResource;
import org.eclipse.ocl.xtext.basecs.BaseCSFactory;
import org.eclipse.ocl.xtext.basecs.BaseCSPackage;
import org.eclipse.ocl.xtext.basecs.ConstraintCS;
import org.eclipse.ocl.xtext.basecs.ElementCS;
import org.eclipse.ocl.xtext.basecs.ParameterCS;
import org.eclipse.ocl.xtext.basecs.PathNameCS;
import org.eclipse.ocl.xtext.basecs.TypedRefCS;
import org.eclipse.ocl.xtext.completeoclcs.ClassifierContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.CompleteOCLCSPackage;
import org.eclipse.ocl.xtext.completeoclcs.CompleteOCLDocumentCS;
import org.eclipse.ocl.xtext.completeoclcs.ContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.OperationContextDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.PackageDeclarationCS;
import org.eclipse.ocl.xtext.completeoclcs.PathNameDeclCS;
import org.eclipse.ocl.xtext.completeoclcs.PropertyContextDeclCS;
import org.eclipse.ocl.xtext.essentialocl.as2cs.EssentialOCLDeclarationVisitor;
import org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSFactory;
import org.eclipse.ocl.xtext.essentialoclcs.EssentialOCLCSPackage;
import org.eclipse.ocl.xtext.essentialoclcs.ExpSpecificationCS;
import com.google.common.collect.Lists;
public class CompleteOCLDeclarationVisitor extends EssentialOCLDeclarationVisitor
{
public CompleteOCLDeclarationVisitor(@NonNull AS2CSConversion context) {
super(context);
}
protected TypedRefCS convertTypeRef(@NonNull TypedElement object) {
Type type = object.getType();
if (type == null) {
return null;
}
TypedRefCS typeRef = context.visitReference(TypedRefCS.class, type, null);
// int upper = object.getUpper().intValue();
// if (upper == 1) {
return typeRef;
// }
// int lower = object.getLower().intValue();
// CollectionTypeCS collectionTypeCS = EssentialOCLCSFactory.eINSTANCE.createCollectionTypeCS();
// collectionTypeCS.setOwnedType(typeRef);
// collectionTypeCS.setName(ElementUtil.getCollectionName(object.isOrdered(), object.isUnique()));
// return collectionTypeCS;
}
protected void gatherPackages(@NonNull List<org.eclipse.ocl.pivot.Package> allPackages, @NonNull List<org.eclipse.ocl.pivot.Package> nestedPackages) {
allPackages.addAll(nestedPackages);
for (org.eclipse.ocl.pivot.Package nestedPackage : nestedPackages) {
List<org.eclipse.ocl.pivot.Package> nestedNestedPackages = nestedPackage.getOwnedPackages();
assert nestedNestedPackages != null;
gatherPackages(allPackages, nestedNestedPackages);
}
}
protected void importPackage(org.eclipse.ocl.pivot.@NonNull Package aPackage) {
context.importNamespace(aPackage, null);
org.eclipse.ocl.pivot.Package nestingPackage = null;
while ((nestingPackage = aPackage.getOwningPackage()) != null) {
aPackage = nestingPackage;
context.importNamespace(aPackage, null);
}
}
@Override
public void postProcess(@NonNull BaseCSResource csResource, @NonNull Map<Namespace, List<String>> importedNamespaces) {
EObject eObject = csResource.getContents().get(0);
if (eObject instanceof CompleteOCLDocumentCS) {
context.createImports((CompleteOCLDocumentCS) eObject, importedNamespaces);
}
}
protected void refreshPathNamedElement(@NonNull PathNameDeclCS csDecl, @NonNull NamedElement namedElement, Namespace scope) {
PathNameCS csPathName = csDecl.getOwnedPathName();
if (csPathName == null) {
csPathName = BaseCSFactory.eINSTANCE.createPathNameCS();
assert csPathName != null;
csDecl.setOwnedPathName(csPathName);
}
context.refreshPathName(csPathName, namedElement, scope);
}
@Override
public ElementCS visitClass(org.eclipse.ocl.pivot.@NonNull Class object) {
List<Constraint> ownedInvariant = object.getOwnedInvariants();
if (ownedInvariant.size() <= 0) {
return null;
}
org.eclipse.ocl.pivot.Package objectPackage = object.getOwningPackage();
ClassifierContextDeclCS csContext = context.refreshElement(ClassifierContextDeclCS.class, CompleteOCLCSPackage.Literals.CLASSIFIER_CONTEXT_DECL_CS, object);
if (objectPackage != null) {
refreshPathNamedElement(csContext, object, objectPackage);
importPackage(objectPackage);
context.refreshList(csContext.getOwnedInvariants(), context.visitDeclarations(ConstraintCS.class, ownedInvariant, null));
}
return csContext;
}
@Override
public ElementCS visitConstraint(@NonNull Constraint object) {
ConstraintCS csElement = context.refreshNamedElement(ConstraintCS.class, BaseCSPackage.Literals.CONSTRAINT_CS, object);
Namespace namespace = PivotUtil.getNamespace(object);
LanguageExpression specification = object.getOwnedSpecification();
if ((specification != null) && (namespace != null)) {
specification.accept(this); // Deep search for references
ExpSpecificationCS csSpec = context.refreshElement(ExpSpecificationCS.class, EssentialOCLCSPackage.Literals.EXP_SPECIFICATION_CS, specification);
csElement.setOwnedSpecification(csSpec);
//
PivotMetamodelManager metamodelManager = context.getMetamodelManager();
PrettyPrintOptions.Global prettyPrintOptions = PrettyPrinter.createOptions(null); //metamodelManager.getPrimaryElement(namespace));
@NonNull List<@NonNull String> newArrayList = Lists.newArrayList("body", "context", "def", "endpackage", "inv", "package", "post", "inv");
prettyPrintOptions.addReservedNames(newArrayList); // FIXME use grammar
prettyPrintOptions.setEnvironmentFactory(metamodelManager.getEnvironmentFactory());
prettyPrintOptions.setLinelength(80);
Resource resource = object.eResource();
AliasAnalysis adapter = resource != null ? AliasAnalysis.getAdapter(resource) : null;
if (adapter != null) {
for (@SuppressWarnings("null")@NonNull CompletePackage aliased : adapter.getAliases()) {
org.eclipse.ocl.pivot.Package primary = aliased.getPrimaryPackage();
if (primary != null) {
String alias = adapter.getAlias(primary, null);
if (alias != null) {
prettyPrintOptions.addAliases(primary, alias);
}
}
}
}
// FIXME BUG 419132 Need to do this in a deferred pass
String expr = PrettyPrinter.print(specification, prettyPrintOptions);
csSpec.setExprString("\t" + expr.trim().replaceAll("\\r", "").replaceAll("\\n", "\n\t\t"));
}
else {
ExpSpecificationCS csSpec = EssentialOCLCSFactory.eINSTANCE.createExpSpecificationCS();
csElement.setOwnedSpecification(csSpec);
csSpec.setExprString("\tnull");
}
return csElement;
}
@Override
public ElementCS visitDataType(@NonNull DataType object) {
return visitType(object);
}
@Override
public ElementCS visitEnumeration(org.eclipse.ocl.pivot.@NonNull Enumeration object) {
return visitType(object);
}
@Override
public ElementCS visitExpressionInOCL(@NonNull ExpressionInOCL object) {
safeVisit(object.getOwnedBody());
return super.visitExpressionInOCL(object);
}
@Override
public ElementCS visitOperation(@NonNull Operation object) {
if ((object.getOwnedPreconditions().size() <= 0) && (object.getBodyExpression() == null) && (object.getOwnedPostconditions().size() <= 0)) {
return null;
}
org.eclipse.ocl.pivot.Class modelType = object.getOwningClass();
org.eclipse.ocl.pivot.Package modelPackage = modelType.getOwningPackage();
org.eclipse.ocl.pivot.Class savedScope = context.setScope(modelType);
OperationContextDeclCS csContext = context.refreshElement(OperationContextDeclCS.class, CompleteOCLCSPackage.Literals.OPERATION_CONTEXT_DECL_CS, object);
refreshPathNamedElement(csContext, object, modelPackage);
// csContext.getNamespace().add(owningType);
csContext.setOwnedType(convertTypeRef(object));
org.eclipse.ocl.pivot.Package owningPackage = object.getOwningClass().getOwningPackage();
if (owningPackage != null) {
importPackage(owningPackage);
}
context.refreshList(csContext.getOwnedParameters(), context.visitDeclarations(ParameterCS.class, object.getOwnedParameters(), null));
context.refreshList(csContext.getOwnedPreconditions(), context.visitDeclarations(ConstraintCS.class, object.getOwnedPreconditions(), null));
context.refreshList(csContext.getOwnedPostconditions(), context.visitDeclarations(ConstraintCS.class, object.getOwnedPostconditions(), null));
context.refreshList(csContext.getOwnedBodies(), context.visitDeclarationAsList(ExpSpecificationCS.class, object.getBodyExpression()));
context.setScope(savedScope);
return csContext;
}
@Override
public ElementCS visitPackage(org.eclipse.ocl.pivot.@NonNull Package object) {
ElementCS csElement = null;
assert object.eContainer() != null;
List<ContextDeclCS> contexts = new ArrayList<ContextDeclCS>();
for (org.eclipse.ocl.pivot.Class type : object.getOwnedClasses()) {
assert type != null;
ClassifierContextDeclCS classifierContext = context.visitDeclaration(ClassifierContextDeclCS.class, type);
if (classifierContext != null) {
contexts.add(classifierContext);
}
for (Operation operation : type.getOwnedOperations()) {
assert operation != null;
OperationContextDeclCS operationContext = context.visitDeclaration(OperationContextDeclCS.class, operation);
if (operationContext != null) {
contexts.add(operationContext);
}
}
for (Property property : type.getOwnedProperties()) {
assert property != null;
PropertyContextDeclCS propertyContext = context.visitDeclaration(PropertyContextDeclCS.class, property);
if (propertyContext != null) {
contexts.add(propertyContext);
}
}
}
if (contexts.size() > 0) {
PackageDeclarationCS csPackage = context.refreshElement(PackageDeclarationCS.class, CompleteOCLCSPackage.Literals.PACKAGE_DECLARATION_CS, object);
// context.refreshList(csPackage.getOwnedType(), context.visitDeclarations(ClassifierCS.class, object.getOwnedType(), null));
refreshPathNamedElement(csPackage, object, PivotUtil.getContainingNamespace(object));
importPackage(object);
context.refreshList(csPackage.getOwnedContexts(), contexts);
csElement = csPackage;
}
return csElement;
}
@Override
public ElementCS visitParameter(@NonNull Parameter object) {
// VariableCS csElement = context.refreshNamedElement(VariableCS.class, EssentialOCLCSPackage.Literals.VARIABLE_CS, object);
ParameterCS csElement = context.refreshNamedElement(ParameterCS.class, BaseCSPackage.Literals.PARAMETER_CS, object);
csElement.setOwnedType(convertTypeRef(object));
return csElement;
}
@Override
public ElementCS visitProperty(@NonNull Property object) {
if (object.getOwnedExpression() == null) {
return null;
}
org.eclipse.ocl.pivot.Class modelType = object.getOwningClass();
org.eclipse.ocl.pivot.Package modelPackage = modelType.getOwningPackage();
org.eclipse.ocl.pivot.Class savedScope = context.setScope(modelType);
PropertyContextDeclCS csContext = context.refreshElement(PropertyContextDeclCS.class, CompleteOCLCSPackage.Literals.PROPERTY_CONTEXT_DECL_CS, object);
if (modelPackage != null) {
refreshPathNamedElement(csContext, object, modelPackage);
// csContext.getNamespace().add(owningType);
csContext.setOwnedType(convertTypeRef(object));
importPackage(modelPackage);
// FIXME derivationInvariants here rather than in Classifier
// context.refreshList(csContext.getRules(), context.visitDeclarations(ContextConstraintCS.class, ownedRule, null));
context.refreshList(csContext.getOwnedDefaultExpressions(), context.visitDeclarationAsList(ExpSpecificationCS.class, object.getOwnedExpression()));
context.setScope(savedScope);
}
return csContext;
}
protected <T extends ConstraintCS> void refreshPropertyConstraints(@NonNull Class<T> csConstraintClass, @NonNull List<@NonNull ? super T> csPropertyConstraints, Property object) {
@Nullable T csConstraint = null;
LanguageExpression defaultExpression = object.getOwnedExpression();
if (defaultExpression != null) {
csConstraint = context.visitDeclaration(csConstraintClass, defaultExpression);
}
if (csConstraint != null) {
csConstraint.setStereotype(PivotConstants.DERIVATION_NAME);
context.refreshList(csPropertyConstraints, Collections.singletonList(csConstraint));
}
else {
csPropertyConstraints.clear();
}
}
@Override
public ElementCS visitModel(@NonNull Model object) {
ElementCS csElement;
assert object.eContainer() == null;
CompleteOCLDocumentCS csDocument = context.refreshElement(CompleteOCLDocumentCS.class, CompleteOCLCSPackage.Literals.COMPLETE_OCL_DOCUMENT_CS, object);
List<org.eclipse.ocl.pivot.Package> allPackages = new ArrayList<org.eclipse.ocl.pivot.Package>();
List<Package> nestedPackages = object.getOwnedPackages();
assert nestedPackages != null;
gatherPackages(allPackages, nestedPackages);
context.refreshList(csDocument.getOwnedPackages(), context.visitDeclarations(PackageDeclarationCS.class, allPackages, null));
csElement = csDocument;
return csElement;
}
@Override
public ElementCS visitType(@NonNull Type object) {
return null;
}
}