blob: 4d6ac9ef88895a483ac08aeab8057a89d05f9c6a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 E.D.Willink 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.codegen.qvti.java;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.analyzer.NameManager;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElementId;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorProperty;
import org.eclipse.ocl.examples.codegen.cgmodel.CGIterator;
import org.eclipse.ocl.examples.codegen.cgmodel.CGOperation;
import org.eclipse.ocl.examples.codegen.cgmodel.CGPackage;
import org.eclipse.ocl.examples.codegen.cgmodel.CGParameter;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId;
import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGVariable;
import org.eclipse.ocl.examples.codegen.generator.TypeDescriptor;
import org.eclipse.ocl.examples.codegen.java.CG2JavaVisitor;
import org.eclipse.ocl.examples.codegen.java.JavaConstants;
import org.eclipse.ocl.examples.codegen.java.JavaLocalContext;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.evaluation.Evaluator;
import org.eclipse.ocl.pivot.ids.ClassId;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
import org.eclipse.ocl.pivot.ids.ElementId;
import org.eclipse.ocl.pivot.ids.PropertyId;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.internal.manager.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiAnalyzer;
import org.eclipse.qvtd.codegen.qvticgmodel.CGAllInstancesOperationCallExp;
import org.eclipse.qvtd.codegen.qvticgmodel.CGEcorePropertyAssignment;
import org.eclipse.qvtd.codegen.qvticgmodel.CGEcoreRealizedVariable;
import org.eclipse.qvtd.codegen.qvticgmodel.CGFunction;
import org.eclipse.qvtd.codegen.qvticgmodel.CGFunctionCallExp;
import org.eclipse.qvtd.codegen.qvticgmodel.CGFunctionParameter;
import org.eclipse.qvtd.codegen.qvticgmodel.CGGuardVariable;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMapping;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMappingCall;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMappingCallBinding;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMappingExp;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMappingLoop;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMiddlePropertyAssignment;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMiddlePropertyCallExp;
import org.eclipse.qvtd.codegen.qvticgmodel.CGPredicate;
import org.eclipse.qvtd.codegen.qvticgmodel.CGPropertyAssignment;
import org.eclipse.qvtd.codegen.qvticgmodel.CGRealizedVariable;
import org.eclipse.qvtd.codegen.qvticgmodel.CGSequence;
import org.eclipse.qvtd.codegen.qvticgmodel.CGTransformation;
import org.eclipse.qvtd.codegen.qvticgmodel.CGTypedModel;
import org.eclipse.qvtd.codegen.qvticgmodel.CGVariablePredicate;
import org.eclipse.qvtd.codegen.qvticgmodel.util.QVTiCGModelVisitor;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.evaluation.AbstractTransformationExecutor;
import org.eclipse.qvtd.pivot.qvtcorebase.Area;
import org.eclipse.qvtd.pivot.qvtcorebase.Assignment;
import org.eclipse.qvtd.pivot.qvtcorebase.BottomPattern;
import org.eclipse.qvtd.pivot.qvtcorebase.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcorebase.RealizedVariable;
import org.eclipse.qvtd.pivot.qvtcorebase.utilities.QVTcoreBaseUtil;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
import org.eclipse.qvtd.pivot.qvtimperative.MappingCall;
import org.eclipse.qvtd.pivot.qvtimperative.evaluation.QVTiTransformationAnalysis;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
/**
* A QVTiCG2JavaVisitor supports generation of Java code from an optimized QVTi CG transformation tree.
*/
public class QVTiCG2JavaVisitor extends CG2JavaVisitor<QVTiCodeGenerator> implements QVTiCGModelVisitor<Boolean>
{
protected class MyTransformationAnalysis extends QVTiTransformationAnalysis
{
protected final @NonNull String classIndex2classIdName;
protected final @NonNull String classIndex2allClassIndexesName;
protected final @NonNull String classIndex2objectsName;
protected final @NonNull String modelObjectsName;
protected MyTransformationAnalysis(@NonNull MetamodelManager metamodelManager, @NonNull CGTransformation cgTransformation) {
super(metamodelManager);
@SuppressWarnings("null")@NonNull Transformation transformation = (Transformation) cgTransformation.getAst();
analyzeTransformation(transformation);
NameManager nameManager = getGlobalContext().getNameManager();
classIndex2classIdName = nameManager.getGlobalSymbolName(null, "classIndex2classId");
classIndex2allClassIndexesName = nameManager.getGlobalSymbolName(null, "classIndex2allClassIndexes");
classIndex2objectsName = "classIndex2objects"; // nameManager.getGlobalSymbolName(null, "classIndex2objects");
modelObjectsName = "modelObjects"; // nameManager.getGlobalSymbolName(null, "modelObjects");
}
public @NonNull String getClassIndex2classIdName() {
return classIndex2classIdName;
}
public @NonNull String getClassIndex2allClassIndexesName() {
return classIndex2allClassIndexesName;
}
public @NonNull String getClassIndex2objectsName() {
return classIndex2objectsName;
}
public @NonNull String getModelObjectsName() {
return modelObjectsName;
}
}
protected final @NonNull QVTiAnalyzer analyzer;
protected final @NonNull CGPackage cgPackage;
protected final @Nullable List<CGValuedElement> sortedGlobals;
private MyTransformationAnalysis transformationAnalysis = null;
public QVTiCG2JavaVisitor(@NonNull QVTiCodeGenerator codeGenerator, @NonNull CGPackage cgPackage,
@Nullable List<CGValuedElement> sortedGlobals) {
super(codeGenerator);
this.analyzer = codeGenerator.getAnalyzer();
this.cgPackage = cgPackage;
this.sortedGlobals = sortedGlobals;
}
protected void appendModelIndex(@Nullable CGTypedModel cgTypedModel) {
if (cgTypedModel == null) {
js.append("-1/*null*/");
}
else {
js.append(cgTypedModel.getModelIndex() + "/*" + cgTypedModel.getName() + "*/");
}
}
protected void doAddRealization(@NonNull CGRealizedVariable cgRealizedVariable) {
RealizedVariable pRealizedVariable = (RealizedVariable)cgRealizedVariable.getAst();
Area pArea = QVTcoreBaseUtil.getContainingArea(pRealizedVariable);
if (pArea != null) {
BottomPattern pBottomPattern = pArea.getBottomPattern();
if (pBottomPattern != null) {
for (Assignment pAssignment : pBottomPattern.getAssignment()) {
if (pAssignment instanceof PropertyAssignment) {
Property pProperty = ((PropertyAssignment)pAssignment).getTargetProperty();
if (pProperty != null) {
Property pOppositeProperty = pProperty.getOpposite();
if ((pOppositeProperty != null) && pOppositeProperty.isComposite()) {
// FIXME must check for null asssignment and correct target return;
}
}
}
}
}
}
CGTypedModel cgTypedModel = cgRealizedVariable.getTypedModel();
//
js.append(transformationAnalysis.getModelObjectsName());
js.append("[");
appendModelIndex(cgTypedModel);
js.append("].add(");
js.appendValueName(cgRealizedVariable);
js.append(");\n");
if (transformationAnalysis != null) {
TypeId typeId = pRealizedVariable.getTypeId();
if (typeId instanceof ClassId) {
Integer classIndex = transformationAnalysis.getAllInstancesClassIndex((ClassId)typeId);
if (classIndex != null) {
js.append(transformationAnalysis.getClassIndex2objectsName());
js.append("[");
js.append(classIndex + "/*" + typeId.getDisplayName() + "*/");
js.append("].add(");
js.appendValueName(cgRealizedVariable);
js.append(");\n");
}
}
}
}
protected String[] doAllInstances() {
// Set<org.eclipse.ocl.pivot.Class> allInstancesClasses = transformationAnalysis.getAllInstancesClasses();
Map<ClassId, Integer> allInstancesClassId2classIndex = transformationAnalysis.getAllInstancesClassId2classIndex();
if (allInstancesClassId2classIndex.size() > 0) {
Map<ClassId, List<ClassId>> instancesClassAnalysis = transformationAnalysis.getInstancesClassAnalysis(transformationAnalysis.getAllInstancesClasses());
//
// Populate a mapping from instancesClass to linear index.
//
// Map<org.eclipse.ocl.pivot.Class, Integer> instancesClass2index = new HashMap<org.eclipse.ocl.pivot.Class, Integer>(instancesClassAnalysis.size());
ClassId[] classIndex2classId = new ClassId[allInstancesClassId2classIndex.size()];
// Collections.sort(sortedList, NameUtil.NameableComparator.INSTANCE);
for (ClassId classId : allInstancesClassId2classIndex.keySet()) {
classIndex2classId[allInstancesClassId2classIndex.get(classId)] = classId;
}
//
// Emit the ClassId array
//
js.append("/*\n");
js.append(" * Array of the ClassIds of each class for which allInstances() may be invoked. Array index is the ClassIndex.\n");
js.append(" */\n");
js.append("private static final ");
js.appendIsRequired(true);
js.append(" ");
js.appendClassReference(ClassId.class);
js.append("[] ");
js.append(transformationAnalysis.getClassIndex2classIdName());
js.append(" = new ");
js.appendClassReference(ClassId.class);
js.append("[]{\n");
js.pushIndentation(null);
for (int i = 0; i < classIndex2classId.length; i++) {
@SuppressWarnings("null")@NonNull ClassId instancesClassId = classIndex2classId[i];
CGTypeId cgTypeId = getCodeGenerator().getAnalyzer().getTypeId(instancesClassId);
js.appendValueName(cgTypeId);
if ((i+1) < classIndex2classId.length) {
js.append(",");
}
js.append("\t\t// " + i + " => " + instancesClassId.getDisplayName() + "\n");
}
js.popIndentation();
js.append("};\n");
//
// Emit the classIndex2allClassIndexes array of arrays
//
js.append("/*\n");
js.append(" * Mapping from each ClassIndex to all the ClassIndexes to which an object of the outer index\n");
js.append(" * may contribute results to an allInstances() invocation.\n");
js.append(" * Non trivial inner arrays arise when one ClassId is a derivation of another and so an\n");
js.append(" * instance of the derived classId contributes to derived and inherited ClassIndexes.\n");
js.append(" */\n");
js.append("private final static ");
js.appendIsRequired(true);
js.append(" ");
js.appendClassReference(int.class);
js.append("[][] ");
js.append(transformationAnalysis.getClassIndex2allClassIndexesName());
js.append(" = new ");
js.appendClassReference(int.class);
js.append("[][] {\n");
js.pushIndentation(null);
for (int i = 0; i < classIndex2classId.length; i++) {
ClassId instancesClassId = classIndex2classId[i];
List<ClassId> superInstancesClassIds = instancesClassAnalysis.get(instancesClassId);
js.append("{");
boolean isFirst = true;
for (ClassId superInstancesClassId : superInstancesClassIds) {
if (!isFirst) {
js.append(",");
}
js.append("" + allInstancesClassId2classIndex.get(superInstancesClassId));
isFirst = false;
}
js.append("}");
if ((i+1) < classIndex2classId.length) {
js.append(",");
}
js.append("\t\t// " + i + " : ");
js.append(instancesClassId.getDisplayName());
js.append(" -> {");
isFirst = true;
for (ClassId superInstancesClassId : superInstancesClassIds) {
if (!isFirst) {
js.append(",");
}
js.append(superInstancesClassId.getDisplayName());
isFirst = false;
}
js.append("}\n");
}
js.popIndentation();
js.append("};\n");
return new String[]{ transformationAnalysis.getClassIndex2classIdName(), transformationAnalysis.getClassIndex2allClassIndexesName()};
}
return null;
}
protected void doConstructor(@NonNull CGTransformation cgTransformation, @Nullable String oppositeName, @Nullable String[] allInstancesNames) {
// String evaluatorName = ((QVTiGlobalContext)globalContext).getEvaluatorParameter().getName();
String evaluatorName = JavaConstants.EVALUATOR_NAME;
String className = cgTransformation.getName();
//
js.append("public " + className + "(final ");
js.appendIsRequired(true);
js.append(" ");
js.appendClassReference(Evaluator.class);
js.append(" " + evaluatorName + ") {\n");
js.pushIndentation(null);
js.append("super(" + evaluatorName + ", new String[] {");
boolean isFirst = true;
for (CGTypedModel cgTypedModel : cgTransformation.getTypedModels()) {
if (!isFirst) {
js.append(", ");
}
String name = cgTypedModel.getName();
js.appendString(name != null ? name : "");
isFirst = false;
}
js.append("}");
if (oppositeName != null) {
js.append(", ");
js.append(oppositeName);
}
else {
js.append(", null");
}
if (allInstancesNames != null) {
js.append(", ");
js.append(allInstancesNames[0]);
js.append(", ");
js.append(allInstancesNames[1]);
}
else {
js.append(", null, null");
}
js.append(");\n");
js.popIndentation();
js.append("}\n");
}
protected void doMiddleOppositeCaches() {
Map<Property, String> toMiddleProperties = getGlobalContext().getToMiddleProperties();
if (toMiddleProperties != null) {
js.append("\n/* Outer-to-Middle Property navigation caches */\n");
Map<String, Property> key2property = new HashMap<String, Property>();
for (Map.Entry<Property, String> entry : toMiddleProperties.entrySet()) {
key2property.put(entry.getValue(), entry.getKey());
}
List<String> sortedKeys = new ArrayList<String>(key2property.keySet());
Collections.sort(sortedKeys);
for (String key : sortedKeys) {
Property property = key2property.get(key);
TypeDescriptor outerTypeDescriptor = context.getBoxedDescriptor(property.getOwningClass().getTypeId());
TypeDescriptor middleTypeDescriptor = context.getBoxedDescriptor(property.getType().getTypeId());
js.append("protected final ");
js.appendIsRequired(true);
js.append(" ");
js.appendClassReference(Map.class, false, middleTypeDescriptor, outerTypeDescriptor);
js.append(" ");
js.append(key);
js.append(" = new ");
js.appendClassReference(HashMap.class, false, middleTypeDescriptor, outerTypeDescriptor);
js.append("();\n");
}
}
}
protected @Nullable String doOppositeCaches() {
Map<Property, Integer> opposites = transformationAnalysis.getOpposites();
if (opposites.size() <= 0) {
return null;
}
NameManager nameManager = getGlobalContext().getNameManager();
List<Property> sortedList = new ArrayList<Property>();
for (Map.Entry<Property, Integer> entry : opposites.entrySet()) {
sortedList.set(entry.getValue().intValue(), entry.getKey());
}
//
// Emit the ClassId array
//
js.append("/*\n");
js.append(" * Array of the PropertyIds of each Property for which unnavigable opposite property navigation may occur.\n");
js.append(" */\n");
String oppositeIndex2propertyIdName = nameManager.getGlobalSymbolName(null, "oppositeIndex2propertyId");
js.append("private static final ");
js.appendIsRequired(true);
js.append(" ");
js.appendClassReference(PropertyId.class);
js.append("[] ");
js.append(oppositeIndex2propertyIdName);
js.append(" = new ");
js.appendClassReference(ClassId.class);
js.append("[]{\n");
js.pushIndentation(null);
for (int i = 0; i < sortedList.size(); i++) {
Property property = sortedList.get(i);
CGElementId cgPropertyId = getCodeGenerator().getAnalyzer().getElementId(property.getPropertyId());
js.appendValueName(cgPropertyId);
if ((i+1) < sortedList.size()) {
js.append(",");
}
js.append("\t\t// " + i + " => " + property.getName() + "\n");
}
js.popIndentation();
js.append("};\n");
return oppositeIndex2propertyIdName;
}
protected void doRun(@NonNull CGTransformation cgTransformation) {
CGMapping cgRootMapping = NameUtil.getNameable(cgTransformation.getMappings(), QVTimperativeUtil.ROOT_MAPPING_NAME);
if (cgRootMapping == null) {
throw new IllegalStateException("Transformation " + cgTransformation.getName() + " has no root mapping");
}
/* List<CGGuardVariable> cgFreeVariables = cgRootMapping.getFreeVariables();
NameManager nameManager = globalContext.getNameManager();
Map<CGParameter, String> listNames = new HashMap<CGParameter, String>();
for (CGGuardVariable cgFreeVariable : cgFreeVariables) {
String nameHint = "LIST_" + cgFreeVariable.getValueName();
String listName = nameManager.getGlobalSymbolName(null, nameHint);
listNames.put(cgFreeVariable, listName);
} */
//
js.append("public boolean run() {\n");
js.pushIndentation(null);
/* for (@NonNull CGGuardVariable cgFreeVariable : cgFreeVariables) {
TypeDescriptor typeDescriptor = context.getTypeDescriptor(cgFreeVariable);
EClassifier eClassifier = ClassUtil.nonNullState(typeDescriptor.getEClassifier());
String qualifiedPackageInterfaceName = genModelHelper.getQualifiedPackageInterfaceName(eClassifier.getEPackage());
String classifierLiteralName = genModelHelper.getLiteralName(eClassifier);
String nameHint = "ECLASS_" + cgFreeVariable.getValueName();
String eClassName = nameManager.getGlobalSymbolName(null, nameHint);
//
js.append("final ");
js.appendClassReference(EClass.class);
js.append(" ");
js.append(eClassName);
js.append(" = ");
js.appendClassReference(qualifiedPackageInterfaceName);
js.append(".Literals." + classifierLiteralName);
js.append(";\n");
//
js.append("assert ");
js.append(eClassName);
js.append(" != null;\n");
//
js.appendClassReference(List.class, true, typeDescriptor);
js.append(" ");
js.append(listNames.get(cgFreeVariable));
js.append(" = getObjectsByType(");
js.appendClassReference(typeDescriptor);
js.append(".class, ");
appendModelIndex(cgFreeVariable.getTypedModel());
js.append(", ");
js.append(eClassName);
js.append(");\n");
}
for (CGGuardVariable cgFreeVariable : cgFreeVariables) {
js.append("for (");
// if (cgFreeVariable.isNonNull()) {
// js.append("@SuppressWarnings(\"null\")@NonNull ");
// }
js.appendClassReference(cgFreeVariable);
js.append(" ");
js.appendValueName(cgFreeVariable);
js.append(" : ");
js.append(listNames.get(cgFreeVariable));
js.append(") {\n");
js.pushIndentation(null);
js.append("if (");
js.appendValueName(cgFreeVariable);
js.append(" != null) {\n");
js.pushIndentation(null);
} */
js.append("return ");
js.append(cgRootMapping.getName());
js.append("(");
/* boolean isFirst = true;
for (CGGuardVariable cgFreeVariable : cgFreeVariables) {
if (!isFirst) {
js.append(", ");
}
js.appendValueName(cgFreeVariable);
isFirst = false;
} */
js.append(");\n");
/* for (@SuppressWarnings("unused") CGGuardVariable cgFreeVariable : cgFreeVariables) {
js.popIndentation();
js.append("}\n");
js.popIndentation();
js.append("}\n");
} */
// js.append("return true;\n");
js.popIndentation();
js.append("}\n");
}
protected @NonNull QVTiGlobalContext getGlobalContext() {
return (QVTiGlobalContext) globalContext;
}
protected @Nullable TypeDescriptor needsTypeCheck(@NonNull CGMappingCallBinding cgMappingCallBinding) {
CGValuedElement value = cgMappingCallBinding.getValue();
TypeDescriptor argumentTypeDescriptor = context.getTypeDescriptor(cgMappingCallBinding);
TypeId pivotTypeId = value.getASTypeId();
if (pivotTypeId instanceof CollectionTypeId) {
pivotTypeId = ((CollectionTypeId)pivotTypeId).getElementTypeId();
}
TypeDescriptor iteratorTypeDescriptor = context.getBoxedDescriptor(ClassUtil.nonNullState(pivotTypeId));
if (argumentTypeDescriptor.isAssignableFrom(iteratorTypeDescriptor)) {
return null;
}
else {
return argumentTypeDescriptor;
}
}
@Override
public @NonNull Boolean visitCGAllInstancesOperationCallExp(@NonNull CGAllInstancesOperationCallExp object) {
return visitCGLibraryOperationCallExp(object);
}
@Override
public @NonNull Boolean visitCGEcorePropertyAssignment(@NonNull CGEcorePropertyAssignment cgPropertyAssignment) {
// Property pivotProperty = cgPropertyCallExp.getReferredProperty();
// CGTypeId cgTypeId = analyzer.getTypeId(pivotProperty.getOwningType().getTypeId());
// JavaTypeDescriptor requiredTypeDescriptor = context.getJavaTypeDescriptor(cgTypeId, false);
EStructuralFeature eStructuralFeature = ClassUtil.nonNullModel(cgPropertyAssignment.getEStructuralFeature());
CGValuedElement cgSlot = getExpression(cgPropertyAssignment.getSlotValue());
CGValuedElement cgInit = getExpression(cgPropertyAssignment.getInitValue());
// Class<?> requiredJavaClass = requiredTypeDescriptor.getJavaClass();
// Method leastDerivedMethod = requiredJavaClass != null ? getLeastDerivedMethod(requiredJavaClass, getAccessor) : null;
// Class<?> unboxedSourceClass = leastDerivedMethod != null ? leastDerivedMethod.getDeclaringClass() : requiredJavaClass;
//
if (!js.appendLocalStatements(cgSlot)) {
return false;
}
if (!js.appendLocalStatements(cgInit)) {
return false;
}
//
if (eStructuralFeature.isMany()) {
String getAccessor = genModelHelper.getGetAccessor(eStructuralFeature);
//
js.appendValueName(cgSlot);
js.append(".");
js.append(getAccessor);
js.append("().addAll(");
js.appendValueName(cgInit);
js.append(");\n");
}
else {
String setAccessor = genModelHelper.getSetAccessor(eStructuralFeature);
//
js.appendValueName(cgSlot);
js.append(".");
js.append(setAccessor);
js.append("(");
js.appendValueName(cgInit);
js.append(");\n");
}
return true;
}
@Override
public @NonNull Boolean visitCGEcoreRealizedVariable(@NonNull CGEcoreRealizedVariable cgRealizedVariable) {
EClassifier eClassifier = cgRealizedVariable.getEClassifier();
EPackage ePackage = eClassifier.getEPackage();
String createMethodName = "create" + eClassifier.getName();
String javaClass;
if (ePackage != null) {
Class<?> factoryClass = genModelHelper.getEcoreFactoryClass(ePackage);
if (factoryClass != null) {
javaClass = factoryClass.getName();
Method factoryMethod = context.getLeastDerivedMethod(factoryClass, createMethodName);
if (factoryMethod != null) {
if (context.getIsNonNull(factoryMethod) == Boolean.TRUE) {
cgRealizedVariable.setNonNull();
};
}
}
else {
javaClass = genModelHelper.getQualifiedFactoryInterfaceName(ePackage);
}
}
else {
javaClass = null;
}
//
js.appendDeclaration(cgRealizedVariable);
js.append(" = ");
js.appendClassReference(javaClass);
// js.appendReferenceTo(localContext.getExecutorType(cgRealizedVariable.getPivotTypeId()));
js.append(".eINSTANCE.");
js.append(createMethodName);
js.append("();\n");
//
js.append("assert ");
js.appendValueName(cgRealizedVariable);
js.append(" != null;\n");
//
doAddRealization(cgRealizedVariable);
return true;
}
@Override
public @NonNull Boolean visitCGFunction(@NonNull CGFunction cgFunction) {
JavaLocalContext<?> localContext2 = globalContext.getLocalContext(cgFunction);
if (localContext2 != null) {
localContext = localContext2;
try {
List<CGParameter> cgParameters = cgFunction.getParameters();
CGValuedElement body = getExpression(cgFunction.getBody());
//
js.append("protected ");
js.appendIsRequired(cgFunction.isRequired());
// js.append(" ");
// js.appendIsCaught(!cgOperation.isInvalid(), cgOperation.isInvalid());
js.append(" ");
ElementId elementId = cgFunction.getTypeId().getElementId();
if (elementId != null) {
TypeDescriptor javaTypeDescriptor = context.getUnboxedDescriptor(elementId);
js.appendClassReference(javaTypeDescriptor);
}
js.append(" ");
js.append(cgFunction.getName());
js.append("(");
boolean isFirst = true;
for (@SuppressWarnings("null")@NonNull CGParameter cgParameter : cgParameters) {
if (!isFirst) {
js.append(", ");
}
js.appendDeclaration(cgParameter);
isFirst = false;
}
js.append(") {\n");
js.pushIndentation(null);
// js.appendCastParameters(localContext2, cgParameters);
// JavaDependencyVisitor dependencyVisitor = new JavaDependencyVisitor(localContext2, null);
// dependencyVisitor.visit(body);
// dependencyVisitor.visitAll(localContext2.getLocalVariables());
// Iterable<CGValuedElement> sortedDependencies = dependencyVisitor.getSortedDependencies();
// for (CGValuedElement cgElement : sortedDependencies) {
// if (!cgElement.isInlined() && cgElement.isConstant() && !cgElement.isGlobal()) {
// cgElement.accept(this);
// }
// }
// FIXME merge locals into AST as LetExps.
if (cgFunction.getBody() != null) {
if (!js.appendLocalStatements(body)) {
return false;
}
js.append("return ");
js.appendValueName(body);
js.append(";\n");
}
else {
TypeId asTypeId = cgFunction.getASTypeId();
if (asTypeId == TypeId.STRING) { // FIXME Fudge for body-less functions
js.append("return \"\";\n");
}
else if (asTypeId == TypeId.REAL) { // FIXME Fudge for body-less functions
js.append("return 0;\n");
}
else if (asTypeId == TypeId.INTEGER) { // FIXME Fudge for body-less functions
js.append("return 0;\n");
}
else if (asTypeId instanceof CollectionTypeId) { // FIXME Fudge for body-less functions
if (js.isUseNullAnnotations()) {
js.append("@SuppressWarnings(\"null\")");
js.appendIsRequired(true);
js.append(" ");
}
if (elementId != null) {
TypeDescriptor javaTypeDescriptor = context.getUnboxedDescriptor(elementId);
js.appendClassReference(javaTypeDescriptor);
}
js.append(" emptyList = ");
js.appendClassReference(Collections.class);
js.append(".emptyList();\n");
js.append("return emptyList;\n");
}
else { // FIXME Fudge for body-less functions
js.append("return \"\";\n");
}
}
js.popIndentation();
js.append("}\n");
}
finally {
localContext = null;
}
}
return true;
}
@Override
public @NonNull Boolean visitCGFunctionCallExp(@NonNull CGFunctionCallExp cgFunctionCallExp) {
Operation pOperation = cgFunctionCallExp.getReferredOperation();
List<CGValuedElement> cgArguments = cgFunctionCallExp.getArguments();
List<Parameter> pParameters = pOperation.getOwnedParameters();
//
for (@SuppressWarnings("null")@NonNull CGValuedElement cgArgument : cgArguments) {
CGValuedElement argument = getExpression(cgArgument);
if (!js.appendLocalStatements(argument)) {
return false;
}
}
//
js.appendDeclaration(cgFunctionCallExp);
js.append(" = ");
js.append(cgFunctionCallExp.getFunction().getName());
js.append("(");
int iMax = Math.min(pParameters.size(), cgArguments.size());
for (int i = 0; i < iMax; i++) {
if (i > 0) {
js.append(", ");
}
CGValuedElement cgArgument = cgArguments.get(i);
CGValuedElement argument = getExpression(cgArgument);
Parameter pParameter = pParameters.get(i);
// CGTypeId cgParameterTypeId = analyzer.getTypeId(pParameter.getTypeId());
TypeDescriptor parameterTypeDescriptor = context.getUnboxedDescriptor(pParameter.getTypeId());
js.appendReferenceTo(parameterTypeDescriptor, argument);
}
js.append(");\n");
return true;
}
@Override
public @NonNull Boolean visitCGFunctionParameter(@NonNull CGFunctionParameter object) {
return visitCGParameter(object);
}
@Override
public @NonNull Boolean visitCGGuardVariable(@NonNull CGGuardVariable object) {
return visitCGParameter(object);
}
@Override
public @NonNull Boolean visitCGMapping(@NonNull CGMapping cgMapping) {
// if ("associationToForeignKeyLM".equals(cgMapping.getName())) {
// System.out.println("Got it");
// }
JavaLocalContext<?> localContext2 = globalContext.getLocalContext(cgMapping);
if (localContext2 != null) {
localContext = localContext2;
try {
String eName = globalContext.getEName();
CGValuedElement cgBody = cgMapping.getBody();
List<CGGuardVariable> cgFreeVariables = cgMapping.getFreeVariables();
//
js.appendCommentWithOCL(null, cgMapping.getAst());
js.append("protected boolean " + cgMapping.getName() + "(");
boolean isFirst = true;
for (@SuppressWarnings("null")@NonNull CGGuardVariable cgFreeVariable : cgFreeVariables) {
if (!isFirst) {
js.append(", ");
}
js.appendDeclaration(cgFreeVariable);
isFirst = false;
}
js.append(") {\n");
js.pushIndentation(null);
if (cgBody.isNonInvalid()) {
js.append("// predicates\n");
cgBody.accept(this);
js.append("return true;\n");
}
else {
js.append("try {\n");
js.pushIndentation(null);
js.append("// predicates\n");
cgBody.accept(this);
js.append("return true;\n");
js.popIndentation();
js.append("}\n");
js.append("catch (");
js.appendClassReference(Exception.class);
js.append(" " + eName + ") {\n");
js.pushIndentation(null);
js.append("return false;\n");
js.popIndentation();
js.append("}\n");
}
js.popIndentation();
js.append("}\n");
}
finally {
localContext = null;
}
}
return true;
}
@Override
public @NonNull Boolean visitCGMappingCall(@NonNull CGMappingCall cgMappingCall) {
MappingCall pMappingCall = (MappingCall) cgMappingCall.getAst();
Mapping pReferredMapping = pMappingCall.getReferredMapping();
if (pReferredMapping == null) {
return true;
}
CGMapping cgReferredMapping = analyzer.getMapping(pReferredMapping);
if (cgReferredMapping == null) {
return true;
}
List<CGMappingCallBinding> cgMappingCallBindings = cgMappingCall.getMappingCallBindings();
for (@SuppressWarnings("null")@NonNull CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
CGValuedElement value = cgMappingCallBinding.getValue();
if (value != null) {
if (!js.appendLocalStatements(value)) {
return false;
}
}
}
//
// Set loopVariable non-null if it needs to be type-checked and cast to a narrower type.
//
for (@SuppressWarnings("null")@NonNull CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
if (checkedType != null) {
js.append("if (");
js.appendValueName(cgMappingCallBinding.getValue());
js.append(" instanceof ");
js.appendClassReference(checkedType);
js.append(") {\n");
js.pushIndentation(null);
}
}
//
// Emit the mapping call.
//
js.append(cgReferredMapping.getName() + "(");
boolean isFirst = true;
for (@SuppressWarnings("null")@NonNull CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
if (!isFirst) {
js.append(", ");
}
TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
if (checkedType != null) {
js.append("(");
js.appendClassReference(checkedType);
js.append(")");
}
js.appendValueName(cgMappingCallBinding.getValue());
isFirst = false;
}
js.append(");\n");
//
// End the type check.
//
for (@SuppressWarnings("null")@NonNull CGMappingCallBinding cgMappingCallBinding : cgMappingCallBindings) {
TypeDescriptor checkedType = needsTypeCheck(cgMappingCallBinding);
if (checkedType != null) {
js.popIndentation();
js.append("}\n");
}
}
return true;
}
@Override
public @NonNull Boolean visitCGMappingCallBinding(@NonNull CGMappingCallBinding object) {
return true;
}
@Override
public @NonNull Boolean visitCGMappingExp(@NonNull CGMappingExp cgMappingExp) {
assert cgMappingExp.getPredicates().isEmpty(); // Get rewritten during JavaPre pass
js.append("// creations\n");
for (CGValuedElement cgRealizedVariable : cgMappingExp.getRealizedVariables()) {
cgRealizedVariable.accept(this);
}
js.append("// assignments\n");
for (CGPropertyAssignment cgAssignment : cgMappingExp.getAssignments()) {
cgAssignment.accept(this);
}
js.append("// mapping statements\n");
CGValuedElement body = cgMappingExp.getBody();
if (body != null) {
body.accept(this);
}
return true;
}
@Override
public @NonNull Boolean visitCGMappingLoop(@NonNull CGMappingLoop cgMappingLoop) {
CGValuedElement source = getExpression(cgMappingLoop.getSource());
CGIterator iterator = cgMappingLoop.getIterators().get(0);
// accumulatorName = getSymbolName(null, init.getValueName());
if (!js.appendLocalStatements(source)) {
return false;
}
// js.appendLocalStatements(iterator);
// js.appendDeclaration(iterator);
// js.append(" = ");
// js.appendValueName(iterator.getInit());
js.append(";\n");
js.append("for (");
// if (iterator.isNonNull()) {
// js.append("@SuppressWarnings(\"null\")@NonNull ");
// }
js.appendClassReference(iterator);
js.append(" ");
js.appendValueName(iterator);
js.append(" : ");
js.appendValueName(source);
js.append(") {\n");
js.pushIndentation(null);
js.append("if (");
js.appendValueName(iterator);
js.append(" != null) {\n");
js.pushIndentation(null);
cgMappingLoop.getBody().accept(this);
js.popIndentation();
js.append("}\n");
js.popIndentation();
js.append("}\n");
return true;
}
@Override
public @NonNull Boolean visitCGMiddlePropertyAssignment(@NonNull CGMiddlePropertyAssignment cgMiddlePropertyAssignment) {
visitCGEcorePropertyAssignment(cgMiddlePropertyAssignment);
Property pReferredProperty = ClassUtil.nonNullModel(cgMiddlePropertyAssignment.getReferredProperty());
assert !pReferredProperty.isImplicit();
CGValuedElement slotValue = cgMiddlePropertyAssignment.getSlotValue();
CGValuedElement initValue = cgMiddlePropertyAssignment.getInitValue();
if ((slotValue != null) && (initValue != null)) {
Map<Property, String> toMiddleProperties = getGlobalContext().getToMiddleProperties();
if (toMiddleProperties != null) {
String cacheName = toMiddleProperties.get(pReferredProperty);
if (cacheName != null) {
js.append(cacheName);
js.append(".put(");
js.appendValueName(initValue);
js.append(", ");
js.appendValueName(slotValue);
js.append(");\n");
}
}
}
return true;
}
@Override
public @NonNull Boolean visitCGMiddlePropertyCallExp(@NonNull CGMiddlePropertyCallExp cgPropertyCallExp) {
Property pivotProperty = cgPropertyCallExp.getReferredProperty();
assert !pivotProperty.isImplicit();
CGValuedElement source = getExpression(cgPropertyCallExp.getSource());
//
if (!js.appendLocalStatements(source)) {
return false;
}
//
js.appendDeclaration(cgPropertyCallExp);
js.append(" = ");
Map<Property, String> toMiddleProperties = getGlobalContext().getToMiddleProperties();
if (toMiddleProperties != null) {
String cacheName = toMiddleProperties.get(pivotProperty);
if (cacheName != null) {
js.appendClassReference(ClassUtil.class);
js.append(".nonNullState (");
js.append(cacheName);
js.append(".get(");
js.appendValueName(source);
js.append("))");
}
js.append(";\n");
}
return true;
}
@Override
public @NonNull Boolean visitCGPredicate(@NonNull CGPredicate cgPredicate) {
boolean booleanCondition = false;
CGValuedElement cgConditionExpression = cgPredicate.getConditionExpression();
if (cgConditionExpression != null) {
booleanCondition = js.is_boolean(cgConditionExpression);
if (!js.appendLocalStatements(cgConditionExpression)) {
return false;
}
}
js.append("if (");
if (booleanCondition) {
js.append("!");
js.appendValueName(cgConditionExpression);
}
else {
js.appendValueName(cgConditionExpression);
js.append(" != ");
js.appendClassReference(ValueUtil.class);
js.append(".TRUE_VALUE");
}
js.append(") {\n");
js.pushIndentation(null);
js.append("return false;\n");
js.popIndentation();
js.append("}\n");
cgPredicate.getThenExpression().accept(this);
return true;
}
@Override
public @NonNull Boolean visitCGPropertyAssignment(@NonNull CGPropertyAssignment cgPropertyAssignment) {
CGExecutorProperty cgExecutorProperty = cgPropertyAssignment.getExecutorProperty();
CGValuedElement slotValue = cgPropertyAssignment.getSlotValue();
CGValuedElement initValue = cgPropertyAssignment.getInitValue();
if ((slotValue != null) && (initValue != null)) {
if (!js.appendLocalStatements(slotValue)) {
return false;
}
if (!js.appendLocalStatements(initValue)) {
return false;
}
js.appendReferenceTo(cgExecutorProperty);
js.append(".initValue(");
js.appendValueName(slotValue);
js.append(", ");
js.appendValueName(initValue);
js.append(");\n");
}
return true;
}
@Override
public @NonNull Boolean visitCGRealizedVariable(@NonNull CGRealizedVariable cgRealizedVariable) {
TypeId typeId = cgRealizedVariable.getASTypeId();
if (typeId != null) {
js.appendDeclaration(cgRealizedVariable);
js.append(" = ");
js.appendReferenceTo(cgRealizedVariable.getExecutorType());
js.append(".createInstance();\n");
}
//
doAddRealization(cgRealizedVariable);
return true;
}
@Override
public @Nullable Boolean visitCGSequence(@NonNull CGSequence cgSequence) {
for (CGValuedElement cgStatement : cgSequence.getStatements()) {
cgStatement.accept(this);
}
return true;
}
@Override
public @NonNull Boolean visitCGTransformation(@NonNull CGTransformation cgTransformation) {
transformationAnalysis = new MyTransformationAnalysis(getMetamodelManager(), cgTransformation);
String className = cgTransformation.getName();
js.append("/**\n");
js.append(" * The " + className + " transformation:\n");
js.append(" * <p>\n");
js.append(" * Construct with an evaluator\n");
js.append(" * <br>\n");
js.append(" * Populate each input model with {@link addRootObjects(String,List)}\n");
js.append(" * <br>\n");
js.append(" * {@link run()}\n");
js.append(" * <br>\n");
js.append(" * Extract each output model with {@link getRootObjects(String)}\n");
js.append(" */\n");
js.append("@SuppressWarnings(\"nls\")\n");
js.append("public class " + className + " extends ");
js.appendClassReference(AbstractTransformationExecutor.class);
js.append("\n");
js.append("{\n");
js.pushIndentation(null);
if (sortedGlobals != null) {
for (CGValuedElement cgElement : sortedGlobals) {
assert cgElement.isGlobal();
cgElement.accept(this);
}
}
doMiddleOppositeCaches();
js.append("\n");
String oppositeName = doOppositeCaches();
js.append("\n");
String[] allInstancesNames = doAllInstances();
js.append("\n");
doConstructor(cgTransformation, oppositeName, allInstancesNames);
js.append("\n");
doRun(cgTransformation);
for (CGOperation cgOperation : cgTransformation.getOperations()) {
js.append("\n");
cgOperation.accept(this);
}
for (CGMapping cgMapping : cgTransformation.getMappings()) {
js.append("\n");
cgMapping.accept(this);
}
js.popIndentation();
js.append("}\n");
transformationAnalysis = null;
return true;
}
@Override
public @NonNull Boolean visitCGTypedModel(@NonNull CGTypedModel object) {
return true;
}
@Override
public @NonNull Boolean visitCGVariablePredicate(@NonNull CGVariablePredicate cgVariablePredicate) {
CGValuedElement cgConditionExpression = ClassUtil.nonNullState(cgVariablePredicate.getConditionExpression());
CGVariable cgPredicateVariable = ClassUtil.nonNullState(cgVariablePredicate.getPredicateVariable());
TypeDescriptor sourceTypeDescriptor = context.getTypeDescriptor(cgConditionExpression);
TypeDescriptor targetTypeDescriptor = context.getTypeDescriptor(cgPredicateVariable);
if (!js.appendLocalStatements(cgConditionExpression)) {
return false;
}
if (targetTypeDescriptor.isAssignableFrom(sourceTypeDescriptor)) {
js.appendDeclaration(cgPredicateVariable);
js.append(" = ");
js.appendReferenceTo(cgConditionExpression);
js.append(";\n");
}
else {
js.append("if (!(");
js.appendValueName(cgConditionExpression);
js.append(" instanceof ");
js.appendClassReference(targetTypeDescriptor);
js.append(")) {\n");
js.pushIndentation(null);
js.append("return false;\n");
js.popIndentation();
js.append("}\n");
js.appendDeclaration(cgPredicateVariable);
js.append(" = ");
js.appendReferenceTo(targetTypeDescriptor, cgConditionExpression);
js.append(";\n");
}
cgVariablePredicate.getThenExpression().accept(this);
return true;
}
}