blob: 570f61b89a9f59eaa45647a7193258dba8140629 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2022 Willink Transformation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.codegen.calling;
import java.lang.reflect.Method;
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.BoxingAnalyzer;
import org.eclipse.ocl.examples.codegen.analyzer.CodeGenAnalyzer;
import org.eclipse.ocl.examples.codegen.calling.AbstractOperationCallingConvention.CGParameterStyle;
import org.eclipse.ocl.examples.codegen.cgmodel.CGBodiedProperty;
import org.eclipse.ocl.examples.codegen.cgmodel.CGEcorePropertyAssignment;
import org.eclipse.ocl.examples.codegen.cgmodel.CGEcorePropertyCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGInvalid;
import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory;
import org.eclipse.ocl.examples.codegen.cgmodel.CGNavigationCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGProperty;
import org.eclipse.ocl.examples.codegen.cgmodel.CGPropertyAssignment;
import org.eclipse.ocl.examples.codegen.cgmodel.CGPropertyCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId;
import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement;
import org.eclipse.ocl.examples.codegen.generator.CodeGenerator;
import org.eclipse.ocl.examples.codegen.generator.TypeDescriptor;
import org.eclipse.ocl.examples.codegen.java.CG2JavaVisitor;
import org.eclipse.ocl.examples.codegen.java.JavaCodeGenerator;
import org.eclipse.ocl.examples.codegen.java.JavaConstants;
import org.eclipse.ocl.examples.codegen.java.JavaStream;
import org.eclipse.ocl.examples.codegen.naming.ClassNameManager;
import org.eclipse.ocl.examples.codegen.naming.ExecutableNameManager;
import org.eclipse.ocl.examples.codegen.utilities.CGUtil;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.NavigationCallExp;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.ids.ElementId;
import org.eclipse.ocl.pivot.internal.library.ConstrainedProperty;
import org.eclipse.ocl.pivot.internal.library.ExplicitNavigationProperty;
import org.eclipse.ocl.pivot.internal.library.ForeignProperty;
import org.eclipse.ocl.pivot.internal.library.StereotypeProperty;
import org.eclipse.ocl.pivot.library.LibraryProperty;
import org.eclipse.ocl.pivot.library.oclany.OclElementOclContainerProperty;
import org.eclipse.ocl.pivot.oclstdlib.OCLstdlibPackage;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
/**
* NativePropertyCallingConvention defines the support for the call of a property realized by native code.
* * </br>
* e.g. as XXXTables.FOREIGN_qualified_class.FC_class.INSTANCE.evaluate(executor, arguments)
*/
public class EcorePropertyCallingConvention extends AbstractPropertyCallingConvention
{
private static final @NonNull EcorePropertyCallingConvention INSTANCE = new EcorePropertyCallingConvention();
public static @NonNull EcorePropertyCallingConvention getInstance(@NonNull Property asProperty) {
INSTANCE.logInstance(asProperty);
return INSTANCE;
}
protected void appendEcoreGet(@NonNull CG2JavaVisitor cg2javaVisitor, @NonNull CGValuedElement cgSource, @NonNull Property asProperty) {
JavaStream js = cg2javaVisitor.getJavaStream();
CGTypeId cgTypeId = cg2javaVisitor.getAnalyzer().getCGTypeId(asProperty.getOwningClass().getTypeId());
ElementId elementId = ClassUtil.nonNullState(cgTypeId.getElementId());
JavaCodeGenerator codeGenerator = cg2javaVisitor.getCodeGenerator();
TypeDescriptor requiredTypeDescriptor = codeGenerator.getUnboxedDescriptor(elementId);
// EStructuralFeature eStructuralFeature = ClassUtil.nonNullState(cgPropertyCallExp.getEStructuralFeature());
EStructuralFeature eStructuralFeature = ClassUtil.nonNullState(cg2javaVisitor.getESObject(asProperty));
String getAccessor;
if (eStructuralFeature == OCLstdlibPackage.Literals.OCL_ELEMENT__OCL_CONTAINER) {
getAccessor = JavaConstants.E_CONTAINER_NAME;
}
else {
getAccessor = codeGenerator.getGenModelHelper().getGetAccessor(eStructuralFeature);
}
Class<?> requiredJavaClass = requiredTypeDescriptor.hasJavaClass();
Method leastDerivedMethod = requiredJavaClass != null ? codeGenerator.getLeastDerivedMethod(requiredJavaClass, getAccessor) : null;
Class<?> unboxedSourceClass;
if (leastDerivedMethod != null) {
unboxedSourceClass = leastDerivedMethod.getDeclaringClass();
}
else {
unboxedSourceClass = requiredJavaClass;
}
if ((unboxedSourceClass != null) && (unboxedSourceClass != Object.class)) {
js.appendAtomicReferenceTo(unboxedSourceClass, cgSource);
}
else {
js.appendAtomicReferenceTo(cgSource);
}
js.append(".");
js.append(getAccessor);
js.append("()");
}
@Override
public @NonNull CGValuedElement createCGNavigationCallExp(@NonNull CodeGenAnalyzer analyzer, @NonNull CGProperty cgProperty,
@NonNull LibraryProperty libraryProperty, @Nullable CGValuedElement cgSource, @NonNull NavigationCallExp asPropertyCallExp) {
CodeGenerator codeGenerator = analyzer.getCodeGenerator();
Property asProperty = CGUtil.getAST(cgProperty);
boolean isRequired = asProperty.isIsRequired();
CGPropertyCallExp cgPropertyCallExp = null;
EStructuralFeature eStructuralFeature = null;
if (libraryProperty instanceof OclElementOclContainerProperty) {
eStructuralFeature = OCLstdlibPackage.Literals.OCL_ELEMENT__OCL_CONTAINER;
}
else if (libraryProperty instanceof StereotypeProperty) {
eStructuralFeature = (EStructuralFeature) asProperty.getESObject();
if (eStructuralFeature != null) {
isRequired = asProperty.isIsRequired();
}
}
else if (libraryProperty instanceof ForeignProperty) {
eStructuralFeature = (EStructuralFeature) asProperty.getESObject();
assert eStructuralFeature == null;
isRequired = asProperty.isIsRequired();
}
else if (libraryProperty instanceof ConstrainedProperty) {
eStructuralFeature = (EStructuralFeature) asProperty.getESObject();
// assert eStructuralFeature != null;
isRequired = asProperty.isIsRequired();
}
else if (libraryProperty instanceof ExplicitNavigationProperty) {
// || (libraryProperty instanceof CompositionProperty)
// || (libraryProperty instanceof ImplicitNonCompositionProperty) // FIXME surely this isn't Ecore
// || (libraryProperty instanceof StaticProperty)
// || (libraryProperty instanceof StereotypeProperty)) {
eStructuralFeature = (EStructuralFeature) asProperty.getESObject();
}
assert eStructuralFeature != null;
CGEcorePropertyCallExp cgEcorePropertyCallExp = CGModelFactory.eINSTANCE.createCGEcorePropertyCallExp();
cgEcorePropertyCallExp.setEStructuralFeature(eStructuralFeature);
cgPropertyCallExp = cgEcorePropertyCallExp;
/* }
else {
CGExecutorPropertyCallExp cgExecutorPropertyCallExp = CGModelFactory.eINSTANCE.createCGExecutorPropertyCallExp();
CGExecutorProperty cgExecutorProperty = analyzer.createExecutorProperty(asProperty);
cgExecutorPropertyCallExp.setExecutorProperty(cgExecutorProperty);
cgExecutorPropertyCallExp.getOwns().add(cgExecutorProperty);
cgPropertyCallExp = cgExecutorPropertyCallExp;
} */
cgPropertyCallExp.setReferredProperty(cgProperty);
analyzer.initAst(cgPropertyCallExp, asPropertyCallExp, true);
cgPropertyCallExp.setRequired(isRequired || codeGenerator.isPrimitive(cgPropertyCallExp));
cgPropertyCallExp.setSource(cgSource);
return cgPropertyCallExp;
}
@Override
public void createCGParameters(@NonNull ExecutableNameManager propertyNameManager, @Nullable ExpressionInOCL initExpression) {
Property asProperty = (Property)propertyNameManager.getASScope();
CGProperty cgProperty = (CGProperty)propertyNameManager.getCGScope();
assert !asProperty.isIsImplicit();
ClassNameManager classNameManager = propertyNameManager.getClassNameManager();
classNameManager.declareEagerName(cgProperty);
super.createCGParameters(propertyNameManager, initExpression);
}
@Override
public boolean generateEcoreBody(@NonNull CG2JavaVisitor cg2javaVisitor, @NonNull CGProperty cgProperty) {
CGValuedElement cgBody = ((CGBodiedProperty)cgProperty).getBody();
if (cgBody == null) {
return false;
}
cgProperty.accept(cg2javaVisitor);
return true;
}
@Override
public boolean generateJavaCall(@NonNull CG2JavaVisitor cg2javaVisitor, @NonNull CGNavigationCallExp cgPropertyCallExp) {
JavaStream js = cg2javaVisitor.getJavaStream();
CGEcorePropertyCallExp cgEcorePropertyCallExp = (CGEcorePropertyCallExp) cgPropertyCallExp;
Property asProperty = ClassUtil.nonNullState(cgPropertyCallExp.getAsProperty());
assert cg2javaVisitor.getESObject(asProperty) == ClassUtil.nonNullState(cgEcorePropertyCallExp.getEStructuralFeature());
//
CGValuedElement source = cg2javaVisitor.getExpression(cgPropertyCallExp.getSource());
if (!js.appendLocalStatements(source)) {
return false;
}
//
Boolean ecoreIsRequired = cg2javaVisitor.getCodeGenerator().isNonNull(asProperty);
boolean isPrimitive = js.isPrimitive(cgPropertyCallExp);
if (!isPrimitive) cg2javaVisitor.appendSuppressWarningsNull(cgPropertyCallExp, ecoreIsRequired);
// js.append("/* " + ecoreIsRequired + " " + isRequired + " */\n");
js.appendDeclaration(cgPropertyCallExp);
js.append(" = ");
appendEcoreGet(cg2javaVisitor, source, asProperty);
js.append(";\n");
return true;
}
@Override
public boolean generateJavaDeclaration(@NonNull CG2JavaVisitor cg2javaVisitor, @NonNull CGProperty cgProperty) {
Property asProperty = CGUtil.getAST(cgProperty);
CGValuedElement cgBody = ((CGBodiedProperty)cgProperty).getBody();
if (cgBody == null) {
return false;
}
JavaStream js = cg2javaVisitor.getJavaStream();
String returnClassName = cg2javaVisitor.getGenModelHelper().getPropertyResultType(asProperty);
js.appendCommentWithOCL(null, cgBody.getAst());
if (JavaCodeGenerator.CALLING_CONVENTION_COMMENTS.isActive()) {
js.append("// " + cgProperty.getCallingConvention() + "\n");
}
js.appendLocalStatements(cgBody);
CGInvalid cgInvalidValue = cgBody.getInvalidValue();
if (cgInvalidValue != null) {
js.append("throw ");
js.appendValueName(cgInvalidValue);
}
else {
TypeDescriptor typeDescriptor = cg2javaVisitor.getCodeGenerator().getTypeDescriptor(cgBody);
// String className = typeDescriptor.getClassName();
// Class<?> javaClass = typeDescriptor.getJavaClass();
js.append("return ");
// if (returnClassName.contains("<")) {
// js.append("(" + returnClassName + ")");
// }
// js.appendValueName(cgBody);
typeDescriptor.appendEcoreValue(js, returnClassName, cgBody);
}
js.append(";");
return true;
}
@Override
public void initCGParameter(@NonNull ExecutableNameManager propertyNameManager) {
Property asProperty = (Property)propertyNameManager.getASScope();
ExpressionInOCL asExpressionInOCL = (ExpressionInOCL)asProperty.getOwnedExpression(); // XXX ??? defaultValue
if (asExpressionInOCL != null) {
propertyNameManager.createCGPropertyParameter(CGParameterStyle.SELF_THIS);
}
}
@Override
public boolean needsGeneration() {
return false;
}
@Override
public void rewriteWithBoxingAndGuards(@NonNull BoxingAnalyzer boxingAnalyzer, @NonNull CGPropertyAssignment cgPropertyAssignment) {
CGEcorePropertyAssignment cgEcorePropertyAssignment = (CGEcorePropertyAssignment)cgPropertyAssignment;
EStructuralFeature eStructuralFeature = cgEcorePropertyAssignment.getEStructuralFeature();
boxingAnalyzer.rewriteAsEcore(cgEcorePropertyAssignment.getOwnedSlotValue(), eStructuralFeature.getEContainingClass());
boxingAnalyzer.rewriteAsEcore(cgEcorePropertyAssignment.getOwnedInitValue(), eStructuralFeature.getEType());
if (eStructuralFeature.isRequired()) {
CGValuedElement cgInit = cgEcorePropertyAssignment.getOwnedInitValue();
TypeDescriptor typeDescriptor = cgInit != null ? boxingAnalyzer.getCodeGenerator().getTypeDescriptor(cgInit) : null;
if ((typeDescriptor == null) || !typeDescriptor.isPrimitive()) {
boxingAnalyzer.rewriteAsGuarded(cgInit, false, "value for " + cgEcorePropertyAssignment.getReferredProperty() + " assignment");
}
}
super.rewriteWithBoxingAndGuards(boxingAnalyzer, cgPropertyAssignment);
}
@Override
protected void rewriteWithResultBoxing(@NonNull BoxingAnalyzer boxingAnalyzer, @NonNull CGNavigationCallExp cgNavigationCallExp) {
CGEcorePropertyCallExp cgEcorePropertyCallExp = (CGEcorePropertyCallExp) cgNavigationCallExp;
if (cgEcorePropertyCallExp.getEStructuralFeature().isMany()) {
boxingAnalyzer.rewriteAsAssertNonNulled(cgEcorePropertyCallExp);
}
}
@Override
protected void rewriteWithSourceBoxing(@NonNull BoxingAnalyzer boxingAnalyzer, @NonNull CGNavigationCallExp cgNavigationCallExp) {
CGEcorePropertyCallExp cgEcorePropertyCallExp = (CGEcorePropertyCallExp) cgNavigationCallExp;
boxingAnalyzer.rewriteAsEcore(cgEcorePropertyCallExp.getSource(), cgEcorePropertyCallExp.getEStructuralFeature().getEContainingClass());
}
}