blob: 01cfa4d94a75380bf7a76b8660505e811a0d47e4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 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.qvtd.compiler.internal.qvtp2qvts;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.DataType;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.ids.OperationId;
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.PivotUtil;
import org.eclipse.ocl.pivot.utilities.StringUtil;
import org.eclipse.ocl.pivot.values.Unlimited;
import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameBuilder;
import org.eclipse.qvtd.compiler.internal.utilities.SymbolNameReservation;
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.qvtcorebase.analysis.DomainUsage;
import org.eclipse.qvtd.pivot.qvtcorebase.analysis.DomainUsageAnalysis;
import org.eclipse.qvtd.pivot.qvtcorebase.analysis.RootDomainUsageAnalysis;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.DOTStringBuilder;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.GraphMLStringBuilder;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
import org.eclipse.qvtd.pivot.schedule.AbstractDatum;
import org.eclipse.qvtd.pivot.schedule.ClassDatum;
import org.eclipse.qvtd.pivot.schedule.MappingAction;
import org.eclipse.qvtd.pivot.schedule.PropertyDatum;
import org.eclipse.qvtd.pivot.schedule.Schedule;
public abstract class SchedulerConstants
{
public static final @NonNull List<@NonNull Connection> EMPTY_CONNECTION_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull EdgeConnection> EMPTY_EDGE_CONNECTION_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull Edge> EMPTY_EDGE_LIST = Collections.emptyList();
//public static final @NonNull List<ExpressionEdge> EMPTY_EXPRESSION_EDGE_LIST = Collections.emptyList();
public static final @NonNull Set<@NonNull SimpleMappingRegion> EMPTY_MAPPING_REGION_SET = Collections.emptySet();
public static final @NonNull List<@NonNull NavigationEdge> EMPTY_NAVIGATION_EDGE_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull Node> EMPTY_NODE_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull NodeConnection> EMPTY_NODE_CONNECTION_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull Region> EMPTY_REGION_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull SimpleEdge> EMPTY_SIMPLE_EDGE_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull SimpleNode> EMPTY_SIMPLE_NODE_LIST = Collections.emptyList();
public static final @NonNull List<@NonNull TypedElement> EMPTY_TYPED_ELEMENT_LIST = Collections.emptyList();
public static @NonNull String getMultiplicity(@NonNull TypedElement typedElement) {
StringBuilder s = new StringBuilder();
Type type = typedElement.getType();
if (type instanceof CollectionType) {
CollectionType collectionType = (CollectionType)type;
Number lower = collectionType.getLower();
Number upper = collectionType.getUpper();
StringUtil.appendMultiplicity(s, lower.intValue(), upper instanceof Unlimited ? -1 : upper.intValue(), collectionType.isIsNullFree());
}
else {
s.append(typedElement.isIsRequired() ? "[1]" : "[?]");
}
return s.toString();
}
/**
* The DependencyGraph to be analyzed
*/
private final @NonNull Schedule dependencyGraph;
private final @NonNull RootDomainUsageAnalysis domainAnalysis;
private final @NonNull QVTp2QVTg qvtp2qvtg;
@SuppressWarnings("unused")
private final @NonNull DomainUsage inputUsage;
private final @NonNull EnvironmentFactory environmentFactory;
private final @NonNull Transformation transformation;
private final @NonNull OperationId collectionSelectByKindId;
private final @NonNull OperationId oclAnyEqualsId;
private final @NonNull OperationId oclAnyOclAsSetId;
private final @NonNull OperationId oclAnyOclAsTypeId;
private final @NonNull OperationId oclAnyOclIsKindOfId;
private final @NonNull OperationId oclElementOclContainerId;
private final @NonNull ClassDatumAnalysis oclVoidClassDatumAnalysis;
private final @NonNull Property oclContainerProperty;
/**
* The extended analysis of each ClassDatum.
*/
private final @NonNull Map<ClassDatum, ClassDatumAnalysis> classDatum2classDatumAnalysis = new HashMap<ClassDatum, ClassDatumAnalysis>();
/**
* The PropertyDatum for each property. // FIXME domains
*/
private final @NonNull Map<Property, PropertyDatum> property2propertyDatum = new HashMap<Property, PropertyDatum>();
/**
* Property used as a navigation to cast to a specific type.
*/
private final @NonNull Map<Type, Property> type2castProperty = new HashMap<Type, Property>();
/**
* Property used as a navigation to iterate collection elementse.
*/
private final @NonNull Map<Type, Property> type2iterateProperty = new HashMap<Type, Property>();
/**
* Property used as an argument role identification.
*/
private final @NonNull Map<String, Property> name2argumentProperty = new HashMap<String, Property>();
/**
* OPeration depency analyzer and analyses.
*/
private @Nullable DependencyAnalyzer dependencyAnalyzer = null;
/**
* Map reserving a unique symbol name per region or connection.
*/
private @NonNull SymbolNameReservation symbolNameReservation = new SymbolNameReservation();
public SchedulerConstants(@NonNull EnvironmentFactory environmentFactory, @NonNull Schedule dependencyGraph, @NonNull QVTp2QVTg qvtp2qvtg) {
this.environmentFactory = environmentFactory;
this.dependencyGraph = dependencyGraph;
this.domainAnalysis = qvtp2qvtg.getDomainUsageAnalysis();
this.qvtp2qvtg = qvtp2qvtg;
this.transformation = ClassUtil.nonNullState(QVTbaseUtil.getContainingTransformation(((MappingAction)dependencyGraph.getActions().get(0)).getMapping()));
//
this.inputUsage = domainAnalysis.getInputUsage();
// int outputMask = ((DomainUsage.Internal)domainAnalysis.getOutputUsage()).getMask();
// int inputMask = checkableMask & ~enforceableMask;
// this.inputUsage = domainAnalysis.getConstantUsage(inputMask);
//
StandardLibrary standardLibrary = environmentFactory.getStandardLibrary();
org.eclipse.ocl.pivot.Class oclAnyType = standardLibrary.getOclAnyType();
org.eclipse.ocl.pivot.Class oclElementType = standardLibrary.getOclElementType();
Operation operation1 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "=");
assert operation1 != null;
oclAnyEqualsId = operation1.getOperationId();
Operation operation2 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "oclAsType");
assert operation2 != null;
oclAnyOclAsTypeId = operation2.getOperationId();
Operation operation3 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "oclIsKindOf");
assert operation3 != null;
oclAnyOclIsKindOfId = operation3.getOperationId();
Operation operation4 = NameUtil.getNameable(oclElementType.getOwnedOperations(), "oclContainer");
assert operation4 != null;
oclElementOclContainerId = operation4.getOperationId();
Operation operation5 = NameUtil.getNameable(oclAnyType.getOwnedOperations(), "oclAsSet");
assert operation5 != null;
oclAnyOclAsSetId = operation5.getOperationId();
Operation operation6 = NameUtil.getNameable(standardLibrary.getCollectionType().getOwnedOperations(), "selectByKind");
assert operation6 != null;
collectionSelectByKindId = operation6.getOperationId();
oclVoidClassDatumAnalysis = getClassDatumAnalysis(standardLibrary.getOclVoidType(), domainAnalysis.getPrimitiveTypeModel());
//
Property candidateOclContainerProperty = NameUtil.getNameable(oclElementType.getOwnedProperties(), "oclContainer");
assert candidateOclContainerProperty != null : "OCL Standard Librarty has no OclElement::oclContainer property";
oclContainerProperty = candidateOclContainerProperty;
//
// Extract salient characteristics from the DependencyGraph.
//
analyzeDatums(dependencyGraph.getDatums());
}
private void analyzeDatums(/*@NonNull*/ List<? extends AbstractDatum> datums) {
for (AbstractDatum abstractDatum : datums) {
if (abstractDatum instanceof ClassDatum) {
ClassDatum classDatum = (ClassDatum)abstractDatum;
// class2classDatum.put(classDatum.getType(), classDatum);
analyzeDatums(classDatum.getPropertyDatums());
}
else if (abstractDatum instanceof PropertyDatum) {
PropertyDatum propertyDatum = (PropertyDatum)abstractDatum;
property2propertyDatum.put(propertyDatum.getProperty(), propertyDatum);
}
analyzeDatums(abstractDatum.getSub());
}
}
protected abstract @NonNull ClassDatumAnalysis createClassDatumAnalysis(@NonNull ClassDatum classDatum);
public @NonNull Property getArgumentProperty(@NonNull String argumentName) {
Property argumentProperty = name2argumentProperty.get(argumentName);
if (argumentProperty == null) {
argumentProperty = QVTimperativeUtil.createProperty(argumentName, getStandardLibrary().getOclAnyType(), true);
name2argumentProperty.put(argumentName, argumentProperty);
}
return argumentProperty;
}
public @NonNull Property getCastProperty(@NonNull Type type) {
Property castProperty = type2castProperty.get(type);
if (castProperty == null) {
castProperty = QVTimperativeUtil.createProperty("«cast»\\n" + type.toString(), type, true);
type2castProperty.put(type, castProperty);
}
return castProperty;
}
public @NonNull ClassDatum getClassDatum(@NonNull TypedElement asTypedElement) {
org.eclipse.ocl.pivot.Class asType = (org.eclipse.ocl.pivot.Class)asTypedElement.getType();
assert asType != null;
Type elementType = QVTbaseUtil.getElementalType(asType);
TypedModel typedModel;
if (elementType instanceof DataType) {
typedModel = getDomainAnalysis().getPrimitiveTypeModel();
}
else {
DomainUsage domainUsage = getDomainUsage(asTypedElement);
assert domainUsage != null;
typedModel = domainUsage.getTypedModel(asTypedElement);
assert typedModel != null;
}
return qvtp2qvtg.getClassDatum(typedModel, asType);
}
public @NonNull ClassDatum getClassDatum(org.eclipse.ocl.pivot.@NonNull Class asType, @NonNull TypedModel typedModel) {
return qvtp2qvtg.getClassDatum(typedModel, asType);
}
public @NonNull ClassDatumAnalysis getClassDatumAnalysis(@NonNull ClassDatum classDatum) {
ClassDatumAnalysis classDatumAnalysis = classDatum2classDatumAnalysis.get(classDatum);
if (classDatumAnalysis == null) {
classDatumAnalysis = createClassDatumAnalysis(classDatum);
classDatum2classDatumAnalysis.put(classDatum, classDatumAnalysis);
}
return classDatumAnalysis;
}
// public @NonNull ClassDatumAnalysis getClassDatumAnalysis(@NonNull Element contextElement, @NonNull Type type) {
// ClassDatum classDatum = getClassDatum(type);
// DomainUsage usage = getDomainUsage(contextElement);
// return getClassDatumAnalysis(classDatum, ClassUtil.nonNullState(usage));
// }
/* public @NonNull ClassDatumAnalysis getClassDatumAnalysis(@NonNull Type type, @NonNull DomainUsage usage) {
ClassDatum classDatum = getClassDatum(type);
// DomainUsage usage = getDomainUsage(contextElement);
return getClassDatumAnalysis(classDatum);
} */
public @NonNull ClassDatumAnalysis getClassDatumAnalysis(@NonNull TypedElement typedElement) {
ClassDatum classDatum = getClassDatum(typedElement);
// DomainUsage usage = getDomainUsage(typedElement);
return getClassDatumAnalysis(classDatum);
}
public @NonNull ClassDatumAnalysis getClassDatumAnalysis(org.eclipse.ocl.pivot.@NonNull Class type, @NonNull TypedModel typedModel) {
ClassDatum classDatum = qvtp2qvtg.getClassDatum(typedModel, type);
return getClassDatumAnalysis(classDatum);
}
public @NonNull Iterable<ClassDatumAnalysis> getClassDatumAnalyses() {
return classDatum2classDatumAnalysis.values();
}
public @NonNull ClassRelationships getClassRelationships() {
return qvtp2qvtg.getClassRelationships();
}
// @SuppressWarnings("null")
// public @NonNull Set<ClassDatum> getClassDatums() {
// return classDatum2classDatumAnalysis.keySet();
// }
public @NonNull OperationId getCollectionSelectByKindId() {
return collectionSelectByKindId;
}
public @NonNull DependencyAnalyzer getDependencyAnalyzer() {
@Nullable
DependencyAnalyzer dependencyAnalyzer2 = dependencyAnalyzer;
if (dependencyAnalyzer2 == null) {
dependencyAnalyzer = dependencyAnalyzer2 = new DependencyAnalyzer(this);
}
return dependencyAnalyzer2;
}
public @NonNull Schedule getDependencyGraph() {
return dependencyGraph;
}
public @NonNull RootDomainUsageAnalysis getDomainAnalysis() {
return domainAnalysis;
}
public @NonNull DomainUsage getDomainUsage(@NonNull Element element) {
DomainUsageAnalysis analysis = domainAnalysis;
Operation operation = PivotUtil.getContainingOperation(element);
if (operation != null) {
analysis = domainAnalysis.getAnalysis(operation);
}
return ClassUtil.nonNullState(analysis.getUsage(element));
}
public @NonNull EnvironmentFactory getEnvironmentFactory() {
return environmentFactory;
}
protected @NonNull URI getGraphsBaseURI() {
return dependencyGraph.eResource().getURI().trimSegments(1).appendSegment("graphs").appendSegment("");
}
public @NonNull Property getIterateProperty(@NonNull Type type) {
Property iterateProperty = type2iterateProperty.get(type);
if (iterateProperty == null) {
iterateProperty = QVTimperativeUtil.createProperty("«iterate»", type, true);
type2iterateProperty.put(type, iterateProperty);
}
return iterateProperty;
}
public @NonNull OperationId getOclAnyEqualsId() {
return oclAnyEqualsId;
}
public @NonNull OperationId getOclAnyOclAsSetId() {
return oclAnyOclAsSetId;
}
public @NonNull OperationId getOclAnyOclAsTypeId() {
return oclAnyOclAsTypeId;
}
public @NonNull OperationId getOclAnyOclIsKindOfId() {
return oclAnyOclIsKindOfId;
}
public @NonNull Property getOclContainerProperty() {
return oclContainerProperty;
}
public @NonNull OperationId getOclElementOclContainerId() {
return oclElementOclContainerId;
}
public @NonNull ClassDatumAnalysis getOclVoidClassDatumAnalysis() {
return oclVoidClassDatumAnalysis;
}
public @NonNull StandardLibrary getStandardLibrary() {
return environmentFactory.getStandardLibrary();
}
public @NonNull Transformation getTransformation() {
return transformation;
}
public @NonNull SymbolNameReservation getSymbolNameReservation() {
return symbolNameReservation;
}
/**
* Return true if a mapping may assign this property in an input model.
*/
public boolean isDirty(@NonNull Property property) {
return domainAnalysis.isDirty(property);
}
public boolean isKnown(@NonNull VariableDeclaration sourceVariable) {
if (sourceVariable.eContainer() == null) { // Synthetic variable
return false;
}
DomainUsage usage = getDomainUsage(sourceVariable);
assert usage != null;
return !usage.isOutput();
}
public @NonNull String reserveSymbolName(@NonNull SymbolNameBuilder symbolNameBuilder, @NonNull Symbolable symbolable) {
return symbolNameReservation.reserveSymbolName(symbolNameBuilder, symbolable);
}
public void writeCallDOTfile(@NonNull ScheduledRegion region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_c") + suffix + ".dot").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
DOTStringBuilder s = new DOTStringBuilder();
region.toCallGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
}
public void writeCallGraphMLfile(@NonNull ScheduledRegion region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_c") + suffix + ".graphml").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
GraphMLStringBuilder s = new GraphMLStringBuilder();
region.toCallGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
}
public void writeDOTfile(@NonNull Region region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_").replace("::", "_") + suffix + ".dot").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
DOTStringBuilder s = new DOTStringBuilder();
region.toGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
}
public void writeGraphMLfile(@NonNull Region region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_").replace("::", "_") + suffix + ".graphml").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
GraphMLStringBuilder s = new GraphMLStringBuilder();
region.toGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
}
public void writeRegionDOTfile(@NonNull ScheduledRegion region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_") + suffix + ".dot").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
DOTStringBuilder s = new DOTStringBuilder();
region.toRegionGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
for (@NonNull Region nestedRegion : region.getRegions()) {
if (nestedRegion instanceof ScheduledRegion) {
writeRegionDOTfile((@NonNull ScheduledRegion)nestedRegion, suffix);
}
}
}
public void writeRegionGraphMLfile(@NonNull ScheduledRegion region, @NonNull String suffix) {
URI baseURI = getGraphsBaseURI();
URI dotURI = URI.createURI(region.getSymbolName().replace("\n", "_").replace("\\n", "_") + suffix + ".graphml").resolve(baseURI);
try {
OutputStream outputStream = URIConverter.INSTANCE.createOutputStream(dotURI);
GraphMLStringBuilder s = new GraphMLStringBuilder();
region.toRegionGraph(s);
outputStream.write(s.toString().getBytes());
outputStream.close();
} catch (IOException e) {
System.err.println("Failed to generate '" + dotURI + "' : " + e.getLocalizedMessage());
}
for (@NonNull Region nestedRegion : region.getRegions()) {
if (nestedRegion instanceof ScheduledRegion) {
writeRegionGraphMLfile((@NonNull ScheduledRegion)nestedRegion, suffix);
}
}
}
}