blob: 8d5b1d427e9f239beb32374ce0111b43d81dceb7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 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
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvts2qvti;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.TreeIterator;
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.Element;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.ids.OperationId;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import org.eclipse.qvtd.compiler.CompilerConstants;
import org.eclipse.qvtd.compiler.CompilerProblem;
import org.eclipse.qvtd.compiler.ProblemHandler;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.AbstractRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.BasicEdgeConnection;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.BasicNodeConnection;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.CyclicScheduledRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Edge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.MappingRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NavigableEdge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.OperationRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Region;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.RootCompositionRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.RootScheduledRegion;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Visitable;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Visitor;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.impl.VariableNodeImpl;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.Region2Depth;
import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameBuilder;
import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameReservation;
import org.eclipse.qvtd.pivot.qvtbase.Domain;
import org.eclipse.qvtd.pivot.qvtbase.Rule;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.TypedModel;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTypedModel;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeHelper;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
public class QVTs2QVTiVisitor extends QVTimperativeHelper implements Visitor<Element>
{
public static final @NonNull TracingOption POLLED_PROPERTIES = new TracingOption(CompilerConstants.PLUGIN_ID, "qvts2qvti/polledProperties");
protected final @NonNull ProblemHandler problemHandler;
protected final @NonNull Transformation qvtpTransformation;
protected final @NonNull SymbolNameReservation symbolNameReservation;
protected final @NonNull Transformation qvtiTransformation;
protected final @NonNull Map<@NonNull TypedModel, @NonNull ImperativeTypedModel> qvtpTypedModel2qvtiTypedModel = new HashMap<>();
protected final @NonNull List<@NonNull ImperativeTypedModel> checkableTypedModels = new ArrayList<>();
protected final @NonNull List<@NonNull ImperativeTypedModel> checkableAndEnforceableTypedModels = new ArrayList<>();
protected final @NonNull List<@NonNull ImperativeTypedModel> enforceableTypedModels = new ArrayList<>();
protected final @NonNull Map<@NonNull Region, @NonNull AbstractRegion2Mapping> region2region2mapping = new HashMap<>();
private @Nullable Set<@NonNull String> reservedNames = null;
private @NonNull Map<@NonNull Operation, @NonNull Operation> qvtpOperation2qvtiOperation = new HashMap<>();
private final @NonNull Region2Depth region2depth = new Region2Depth();
private final @NonNull Set<@NonNull Transformation> otherTransformations = new HashSet<>(); // Workaround Bug 481658
private final @NonNull Map<@NonNull String, @NonNull Operation> name2operation = new HashMap<>(); // Workaround Bug 481658
private /*@LazyNonNull*/ ImperativeTypedModel qvtiMiddleTypedModel = null;
public QVTs2QVTiVisitor(@NonNull ProblemHandler problemHandler, @NonNull EnvironmentFactory environmentFactory, @NonNull Transformation qvtpTransformation, @NonNull SymbolNameReservation symbolNameReservation) {
super(environmentFactory);
this.problemHandler = problemHandler;
this.qvtpTransformation = qvtpTransformation;
this.symbolNameReservation = symbolNameReservation;
String transformationName = qvtpTransformation.getName();
assert transformationName != null;
qvtiTransformation = QVTimperativeUtil.createTransformation(transformationName);
createTypedModels();
// analyzeConnections();
}
private void accumulateOperations(@NonNull Transformation transformation) {
if (otherTransformations.add(transformation)) {
for (TreeIterator<EObject> tit = transformation.eAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof Operation) {
Operation operation = (Operation) eObject;
String name = String.valueOf(operation);
name2operation.put(name, operation);
}
}
}
}
/* private void analyzeConnection(@NonNull Connection connection) {
assert connection.isPassed();
Region commonRegion = null;
for (Node source : connection.getSources()) {
Region sourceRegion = source.getRegion();
if (commonRegion == null) {
commonRegion = sourceRegion;
}
else {
commonRegion = region2depth.getCommonRegion(commonRegion, sourceRegion);
}
}
assert commonRegion != null;
connection2commonRegion.put(connection, commonRegion);
List<Connection> connections = region2connections.get(commonRegion);
if (connections == null) {
connections = new ArrayList<Connection>();
region2connections.put(commonRegion, connections);
}
connections.add(connection);
}
private void analyzeConnections() {
for (Region region : regionOrdering.getRegionOrdering()) {
if (region.isConnectionRegion()) {
Connection connectionRegion = (Connection)region;
if (connectionRegion.isPassed()) {
analyzeConnection(connectionRegion);
}
}
}
} */
public void addProblem(@NonNull CompilerProblem problem) {
problemHandler.addProblem(problem);
}
public @Nullable Operation create(@Nullable Operation pOperation) {
if (pOperation == null) {
return null;
}
Operation iOperation = qvtpOperation2qvtiOperation.get(pOperation);
if (iOperation == null) {
Transformation containingTransformation = QVTbaseUtil.getContainingTransformation(pOperation);
if (containingTransformation == qvtpTransformation) {
iOperation = EcoreUtil.copy(pOperation);
assert iOperation != null;
qvtpOperation2qvtiOperation.put(pOperation, iOperation);
qvtiTransformation.getOwnedOperations().add(iOperation);
}
else { // FIXME Foreign queries ...
// FIXME working around Bug 481658
if (containingTransformation != null) {
accumulateOperations(containingTransformation);
}
Operation otherOperation = name2operation.get(pOperation.toString());
if (otherOperation != null) {
iOperation = EcoreUtil.copy(pOperation);
assert iOperation != null;
qvtpOperation2qvtiOperation.put(pOperation, iOperation);
qvtiTransformation.getOwnedOperations().add(iOperation);
}
else {
iOperation = pOperation;
qvtpOperation2qvtiOperation.put(pOperation, iOperation);
}
}
}
return iOperation;
}
public void createRegion2Mapping(@NonNull Region region) {
AbstractRegion2Mapping region2mapping = region2region2mapping.get(region);
assert region2mapping == null : "Re-AbstractRegion2Mapping for " + region;
// assert !region.isConnectionRegion();
if (region.isCyclicScheduledRegion()) {
region2mapping = new CyclicScheduledRegion2Mapping(this, (CyclicScheduledRegion)region);
}
else if (region.isRootCompositionRegion()) {
region2mapping = new RootRegion2Mapping(this, (RootCompositionRegion)region);
}
else {
region2mapping = new BasicRegion2Mapping(this, region);
}
region2region2mapping.put(region, region2mapping);
qvtiTransformation.getRule().add(region2mapping.getMapping());
region.accept(this);
// for (@SuppressWarnings("null")@NonNull Region childRegion : region.getCalledRegions()) {
// if (region2region2mapping.get(childRegion) == null) {
// createRegion2Mapping(childRegion);
// }
// }
}
protected void createTypedModels() {
for (TypedModel qvtpTypedModel : qvtpTransformation.getModelParameter()) {
String typedModelName = qvtpTypedModel.getName();
assert typedModelName != null;
ImperativeTypedModel qvtiTypedModel = QVTimperativeUtil.createTypedModel(typedModelName);
qvtiTypedModel.getUsedPackage().addAll(qvtpTypedModel.getUsedPackage());
if (QVTimperativeUtil.MIDDLE_DOMAIN_NAME.equals(typedModelName)) {
assert qvtiMiddleTypedModel == null;
qvtiMiddleTypedModel = qvtiTypedModel;
}
qvtpTypedModel2qvtiTypedModel.put(qvtpTypedModel, qvtiTypedModel);
qvtiTransformation.getModelParameter().add(qvtiTypedModel);
}
for (Rule rule : qvtpTransformation.getRule()) {
for (Domain domain : rule.getDomain()) {
if (domain.isIsCheckable()) {
ImperativeTypedModel checkableTypedModel = qvtpTypedModel2qvtiTypedModel.get(domain.getTypedModel());
if ((checkableTypedModel != null) && !checkableAndEnforceableTypedModels.contains(checkableTypedModel)) {
checkableTypedModel.setIsChecked(true);
if (enforceableTypedModels.contains(checkableTypedModel)) {
checkableAndEnforceableTypedModels.add(checkableTypedModel);
enforceableTypedModels.remove(checkableTypedModel);
}
else if (!checkableTypedModels.contains(checkableTypedModel)) {
checkableTypedModels.add(checkableTypedModel);
}
}
}
if (domain.isIsEnforceable()) {
ImperativeTypedModel enforceableTypedModel = qvtpTypedModel2qvtiTypedModel.get(domain.getTypedModel());
if ((enforceableTypedModel != null) && !checkableAndEnforceableTypedModels.contains(enforceableTypedModel)) {
enforceableTypedModel.setIsEnforced(true);
if (checkableTypedModels.contains(enforceableTypedModel)) {
checkableAndEnforceableTypedModels.add(enforceableTypedModel);
checkableTypedModels.remove(enforceableTypedModel);
}
else if (!enforceableTypedModels.contains(enforceableTypedModel)) {
enforceableTypedModels.add(enforceableTypedModel);
}
}
}
}
}
}
// public @NonNull ChainNode getChain(@NonNull Region region) {
// return chainGraph.getChain(region);
// }
public @NonNull EnvironmentFactory getEnvironmentFactory() {
return environmentFactory;
}
public @NonNull Operation getEqualsOperation() {
StandardLibrary standardLibrary = getStandardLibrary();
org.eclipse.ocl.pivot.Class oclAnyType = standardLibrary.getOclAnyType();
Operation operation1 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "=");
assert operation1 != null;
OperationId oclAnyEqualsId = operation1.getOperationId();
return environmentFactory.getIdResolver().getOperation(oclAnyEqualsId);
}
@Override
public @NonNull PivotMetamodelManager getMetamodelManager() {
return super.getMetamodelManager();
}
public @NonNull Operation getNotEqualsOperation() {
StandardLibrary standardLibrary = getStandardLibrary();
org.eclipse.ocl.pivot.Class oclAnyType = standardLibrary.getOclAnyType();
Operation operation1 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "<>");
assert operation1 != null;
OperationId oclAnyEqualsId = operation1.getOperationId();
return environmentFactory.getIdResolver().getOperation(oclAnyEqualsId);
}
public @Nullable ImperativeTypedModel getQVTiTypedModel(@Nullable TypedModel qvtpTypedModel) {
if (qvtpTypedModel == null) {
assert qvtiMiddleTypedModel != null;
return qvtiMiddleTypedModel;
}
return qvtpTypedModel2qvtiTypedModel.get(qvtpTypedModel);
}
public @NonNull Region2Depth getRegion2Depth() {
return region2depth;
}
public @NonNull AbstractRegion2Mapping getRegion2Mapping(@NonNull Region region) {
AbstractRegion2Mapping region2mapping = region2region2mapping.get(region);
assert region2mapping != null : "No AbstractRegion2Mapping for " + region;
return region2mapping;
}
public @NonNull Set<@NonNull String> getReservedNames() {
Set<@NonNull String> reservedNames2 = reservedNames;
if (reservedNames2 == null) {
reservedNames = reservedNames2 = new HashSet<@NonNull String>();
reservedNames2.add(ClassUtil.nonNull(qvtpTransformation.getName()));
for (TypedModel typedModel : qvtpTransformation.getModelParameter()) {
reservedNames2.add(ClassUtil.nonNullState(typedModel.getName()));
}
for (Operation operation : qvtpTransformation.getOwnedOperations()) {
reservedNames2.add(ClassUtil.nonNull(operation.getName()));
}
for (Property property : qvtpTransformation.getOwnedProperties()) {
reservedNames2.add(ClassUtil.nonNull(property.getName()));
}
}
return reservedNames2;
}
public @NonNull StandardLibrary getStandardLibrary() {
return environmentFactory.getStandardLibrary();
}
public @NonNull Transformation getTransformation() {
return qvtiTransformation;
}
public @NonNull String reserveSymbolName(@NonNull SymbolNameBuilder symbolNameBuilder, @NonNull Object object) {
return symbolNameReservation.reserveSymbolName(symbolNameBuilder, object);
}
// private @NonNull Node selectHeadNode(@NonNull List<Node> headNodes) {
// return headNodes.get(0); // FIXME best
// }
@Override
public @Nullable Element visiting(@NonNull Visitable visitable) {
throw new UnsupportedOperationException(getClass().getSimpleName() + ": " + visitable.getClass().getSimpleName());
}
@Override
public Element visitBasicEdgeConnection(@NonNull BasicEdgeConnection basicEdgeConnection) {
return visiting(basicEdgeConnection);
}
@Override
public Element visitBasicNodeConnection(@NonNull BasicNodeConnection basicNodeConnection) {
return visiting(basicNodeConnection);
}
@Override
public @Nullable Element visitCyclicScheduledRegion(@NonNull CyclicScheduledRegion cyclicScheduledRegion) {
List<@NonNull Region> callableRegions = new ArrayList<@NonNull Region>();
for (@NonNull Region region : cyclicScheduledRegion.getRegions()) {
if (region.isOperationRegion()) {}
// else if (region.isConnectionRegion()) {
// callableRegions.add(region);
// }
else {
callableRegions.add(region);
}
}
List<@NonNull Region> sortedRegions = AbstractRegion.EarliestRegionComparator.sort(callableRegions);
for (@NonNull Region region : sortedRegions) {
// if (!region.isConnectionRegion()) {
createRegion2Mapping(region);
// }
}
for (@NonNull Region region : sortedRegions) {
// if (!region.isConnectionRegion()) {
AbstractRegion2Mapping region2Mapping = getRegion2Mapping(region);
region2Mapping.createStatements();
// }
}
AbstractRegion2Mapping region2mapping = getRegion2Mapping(cyclicScheduledRegion);
return region2mapping.getMapping();
}
@Override
public Element visitEdge(@NonNull Edge edge) {
return visiting(edge);
}
@Override
public @Nullable Element visitMappingRegion(@NonNull MappingRegion mappingRegion) {
AbstractRegion2Mapping region2mapping = getRegion2Mapping(mappingRegion);
return region2mapping.getMapping();
}
@Override
public Element visitNavigableEdge(@NonNull NavigableEdge navigableEdge) {
return visitEdge(navigableEdge);
}
@Override
public Element visitNode(@NonNull Node node) {
return visiting(node);
}
@Override
public @Nullable Element visitOperationRegion(@NonNull OperationRegion operationRegion) {
return visiting(operationRegion);
}
@Override
public Element visitRegion(@NonNull Region region) {
return visiting(region);
}
@Override
public @Nullable Element visitRootCompositionRegion(@NonNull RootCompositionRegion rootCompositionRegion) {
AbstractRegion2Mapping region2mapping = getRegion2Mapping(rootCompositionRegion);
Mapping mapping = region2mapping.getMapping();
// for (@SuppressWarnings("null")@NonNull List<Node> headNodes : rootContainmentRegion.getHeadNodeGroups()) {
// Node headNode = selectHeadNode(headNodes);
// Variable headVariable = region2mapping.getGuardVariable(headNode);
// getGuardPattern(mapping).getVariable().add(guardVariable);
// }
return mapping;
}
@Override
public @Nullable Element visitRootScheduledRegion(@NonNull RootScheduledRegion rootScheduledRegion) {
// String name = rootRegion.getName();
//
List<@NonNull Region> callableRegions = new ArrayList<@NonNull Region>();
for (@NonNull Region region : rootScheduledRegion.getRegions()) {
if (region.isOperationRegion()) {}
// else if (region.isConnectionRegion()) {
// callableRegions.add(region);
// }
else {
callableRegions.add(region);
}
}
List<@NonNull Region> sortedRegions = AbstractRegion.EarliestRegionComparator.sort(callableRegions);
for (@NonNull Region region : sortedRegions) {
// if (!region.isConnectionRegion()) {
createRegion2Mapping(region);
// }
}
// Region rootRegion = regionOrdering.getRootRegion();
// chainGraph = new ChainGraph(region2depth, rootRegion, regionOrdering.getSchedulableOrdering());
// @SuppressWarnings("null")@NonNull URI baseURI = qvtpTransformation.eResource().getURI();
// chainGraph.writeChainDOTfile(baseURI, "c");
// chainGraph.writeChainGraphMLfile(baseURI, "c");
//
/* Map<TypedModel, Map<Property, List<NavigationEdge>>> typedModel2property2realizedEdges = new HashMap<TypedModel, Map<Property, List<NavigationEdge>>>();
for (@SuppressWarnings("null")@NonNull Region region : sortedRegions) {
AbstractRegion2Mapping region2Mapping = getRegion2Mapping(region);
region2Mapping.computeRealizations(typedModel2property2realizedEdges);
}
boolean doDebug = QVTs2QVTiVisitor.POLLED_PROPERTIES.isActive();
if (doDebug) {
for (TypedModel typedModel : typedModel2property2realizedEdges.keySet()) {
Map<Property, List<NavigationEdge>> property2realizedEdges = typedModel2property2realizedEdges.get(typedModel);
for (Property property : property2realizedEdges.keySet()) {
List<NavigationEdge> realizedEdges = property2realizedEdges.get(property);
for (NavigationEdge realizedEdge : realizedEdges) {
Region region = realizedEdge.getRegion();
QVTs2QVTiVisitor.POLLED_PROPERTIES.println(typedModel + " enforced at " + region.getEarliestIndex()
+ ".." + region.getLatestIndex() + " for " + property + " in " + region);
}
}
}
}
for (@SuppressWarnings("null")@NonNull Region region : sortedRegions) {
AbstractRegion2Mapping region2Mapping = getRegion2Mapping(region);
region2Mapping.checkAndEnforceRealizations(typedModel2property2realizedEdges);
} */
for (@NonNull Region region : sortedRegions) {
// if (!region.isConnectionRegion()) {
AbstractRegion2Mapping region2Mapping = getRegion2Mapping(region);
region2Mapping.createStatements();
// }
}
ECollections.sort(qvtiTransformation.getRule(), NameUtil.NameableComparator.INSTANCE);
/* org.eclipse.ocl.pivot.Package rootPackage = PivotUtil.createPackage("", "yy", "zz", null);
rootPackage.getOwnedClasses().add(qvtiTransformation);
Model model = PivotUtil.createModel(ImperativeModel.class, QVTimperativePackage.Literals.IMPERATIVE_MODEL, null);
model.getOwnedPackages().add(rootPackage);
List<@NonNull Namespace> importedNamespaces = new ArrayList<@NonNull Namespace>();
for (@NonNull TypedModel typedModel : qvtpTypedModel2qvtiTypedModel.values()) {
for (Namespace importedNamespace : ClassUtil.nullFree(typedModel.getUsedPackage())) {
if (!importedNamespaces.contains(importedNamespace)) {
importedNamespaces.add(importedNamespace);
}
}
}
Collections.sort(importedNamespaces, NameUtil.NAMEABLE_COMPARATOR);
List<Import> ownedImports = model.getOwnedImports();
for (@NonNull Namespace importedNamespace : importedNamespaces) {
ownedImports.add(createImport(null, importedNamespace));
} */
return qvtiTransformation;
}
@Override
public Element visitVariableNode(@NonNull VariableNodeImpl variableNode) {
return visitNode(variableNode);
}
}