blob: 494b4d7659c396d04c49f2df6b4a8a3cae63e464 [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.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.analyzer.CodeGenAnalyzer;
import org.eclipse.ocl.examples.codegen.cgmodel.CGClass;
import org.eclipse.ocl.examples.codegen.cgmodel.CGFinalVariable;
import org.eclipse.ocl.examples.codegen.cgmodel.CGIndexExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory;
import org.eclipse.ocl.examples.codegen.cgmodel.CGNativeOperationCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGNativePropertyCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGOperation;
import org.eclipse.ocl.examples.codegen.cgmodel.CGParameter;
import org.eclipse.ocl.examples.codegen.cgmodel.CGProperty;
import org.eclipse.ocl.examples.codegen.cgmodel.CGPropertyAssignment;
import org.eclipse.ocl.examples.codegen.cgmodel.CGSequence;
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.cgmodel.CGVariableExp;
import org.eclipse.ocl.examples.codegen.java.JavaLanguageSupport;
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.Operation;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.library.AbstractOperation;
import org.eclipse.ocl.pivot.library.LibraryFeature;
import org.eclipse.ocl.pivot.library.LibraryOperation;
/**
* ImplementedOperationCallingConvention defines the support for the call of an operation implemented by a Java class.
*/
public class ImplementedOperationCallingConvention extends ExternalOperationCallingConvention
{
private static final @NonNull ImplementedOperationCallingConvention INSTANCE = new ImplementedOperationCallingConvention();
public static @NonNull ImplementedOperationCallingConvention getInstance(@NonNull Operation asOperation, boolean maybeVirtual) {
INSTANCE.logInstance(asOperation, maybeVirtual);
return INSTANCE;
}
public static class ImplementedConstructorOperationCallingConvention extends AbstractConstructorOperationCallingConvention
{
private static final @NonNull ImplementedConstructorOperationCallingConvention INSTANCE = new ImplementedConstructorOperationCallingConvention();
public static @NonNull ImplementedConstructorOperationCallingConvention getInstance(org.eclipse.ocl.pivot.@NonNull Class asClass) {
INSTANCE.logInstance(asClass);
return INSTANCE;
}
@Override
public void createCGBody(@NonNull CodeGenAnalyzer analyzer, @NonNull CGOperation cgConstructor) { // merge with super
Operation asOperation = CGUtil.getAST(cgConstructor);
Operation asOrigin = analyzer.getOriginalOperation(cgConstructor);
assert asOperation.getBodyExpression() == null;
CGClass cgEntryClass = CGUtil.getContainingClass(cgConstructor);
List<@NonNull CGProperty> cgProperties = CGUtil.getPropertiesList(cgEntryClass);
ExecutableNameManager operationNameManager = analyzer.getOperationNameManager(cgConstructor, asOperation, asOrigin);
//
// PivotHelper asHelper = analyzer.getASHelper();
CGParameter cgEntryBoxedValuesParameter = operationNameManager.getBoxedValuesParameter();
CGTypeId cgTypeId = analyzer.getCGTypeId(TypeId.OCL_VOID);
CGParameter cgThisParameter = operationNameManager.getThisParameter();
CGSequence cgSequence = CGModelFactory.eINSTANCE.createCGSequence();
List<@NonNull CGValuedElement> cgSourceAndArguments = new ArrayList<>();
List<@NonNull CGValuedElement> cgStatements = CGUtil.getOwnedStatementsList(cgSequence);
Stack<@NonNull CGFinalVariable> cgLetVariables = new Stack<>();
//
// Unpack boxedValues and assign properties.
//
int iInclusiveMax = cgProperties.size()-1;
for (int i = 0; i <= iInclusiveMax; i++) {
CGProperty cgProperty = cgProperties.get(i);
Property asProperty = CGUtil.getAST(cgProperty);
CGValuedElement cgInitValue;
if (i < iInclusiveMax) {
//
// Unpack boxedValues[i] to a let-variable
//
CGVariableExp cgVariableExp = analyzer.createCGVariableExp(cgEntryBoxedValuesParameter);
CGIndexExp cgCastExp = analyzer.createCGIndexExp(cgVariableExp, i, asProperty);
CGFinalVariable cgLetVariable = (CGFinalVariable)operationNameManager.lazyGetCGVariable(asProperty);
analyzer.setCGVariableInit(cgLetVariable, cgCastExp);
cgProperty.getNameResolution().addCGElement(cgLetVariable);
cgLetVariables.push(cgLetVariable);
cgInitValue = analyzer.createCGVariableExp(cgLetVariable);
// if (i > 0) { // Skip self ?? conditionalize on static
cgSourceAndArguments.add(analyzer.createCGVariableExp(cgLetVariable));
// }
}
else {
//
// Compute value
//
LibraryFeature asImplementation = asOrigin.getImplementation();
Field field = null;
Method method = null;
if (asImplementation instanceof JavaLanguageSupport.JavaNativeOperation) {
method = ((JavaLanguageSupport.JavaNativeOperation)asImplementation).getMethod();
}
else if (asImplementation instanceof AbstractOperation) {
AbstractOperation abstractOperation = (AbstractOperation)asImplementation;
field = abstractOperation.getInstanceField();
method = abstractOperation.getEvaluateMethod(asOrigin);
int j = 0;
for (Class<?> jParameterType : method.getParameterTypes()) {
if (jParameterType == Executor.class) {
CGVariable cgExecutorVariable = operationNameManager.lazyGetExecutorVariable();
cgSourceAndArguments.add(j, analyzer.createCGVariableExp(cgExecutorVariable));
}
else if (jParameterType == TypeId.class) {
CGValuedElement cgConstantExp = analyzer.createCGConstantExp(analyzer.getCGTypeId(asOrigin.getTypeId()));
cgSourceAndArguments.add(j, cgConstantExp);
}
j++;
}
}
assert method != null; // XXX
NativePropertyCallingConvention nativePropertyCallingConvention = NativePropertyCallingConvention.getInstance(asOperation);
NativeOperationCallingConvention nativeOperationCallingConvention = NativeOperationCallingConvention.getInstance(asOperation, false);
CGNativeOperationCallExp cgNativeOperationCallExp = analyzer.createCGNativeOperationCallExp(method, nativeOperationCallingConvention);
cgNativeOperationCallExp.setTypeId(analyzer.getCGTypeId(asOrigin.getTypeId()));
cgNativeOperationCallExp.setRequired(asOrigin.isIsRequired());
cgNativeOperationCallExp.getArguments().addAll(cgSourceAndArguments);
if (field != null) {
CGNativePropertyCallExp cgNativePropertyCallExp = analyzer.createCGNativePropertyCallExp(field, nativePropertyCallingConvention);
cgNativePropertyCallExp.setSource(null);
// cgNativePropertyCallExp.setTypeId(analyzer.getCGTypeId(asOrigin.getOwningClass().getTypeId()));
// cgNativePropertyCallExp.setRequired(true);
cgNativeOperationCallExp.setCgThis(cgNativePropertyCallExp);
}
// OCLExpression asEntryResult = asHelper.createOperationCallExp(null, asOrigin, asArguments);
// OCLExpression asEntryResult = asHelper.createIntegerLiteralExp(77) ; //asEntryExpressionInOCL.getOwnedBody();
cgInitValue = cgNativeOperationCallExp;
}
//
// Assign property from let-variable / computation
//
CGPropertyAssignment cgPropertyAssignment = CGModelFactory.eINSTANCE.createCGPropertyAssignment();
cgPropertyAssignment.setAst(asProperty);
cgPropertyAssignment.setTypeId(cgTypeId);
cgPropertyAssignment.setOwnedSlotValue(analyzer.createCGVariableExp(cgThisParameter));
cgPropertyAssignment.setReferredProperty(cgProperty);
cgPropertyAssignment.setOwnedInitValue(cgInitValue);
// cgPropertyAssignment.setAsProperty(asProperty);
cgStatements.add(cgPropertyAssignment);
// cgProperty.getNameResolution().addCGElement(cgCastExp);
}
//
// Wrap unpacked let-variables as let-expressions around sequenced assignments.
//
CGValuedElement cgBody = cgSequence;
while (!cgLetVariables.isEmpty()) {
CGFinalVariable cgLetVariable = cgLetVariables.pop();
cgBody = analyzer.createCGLetExp(cgLetVariable, cgBody);
}
cgConstructor.setBody(cgBody);
}
@Override
protected @NonNull ASParameterStyle @NonNull [] getASParameterStyles(@NonNull TypedElement asOrigin) {
// TODO Auto-generated method stub
return super.getASParameterStyles(asOrigin);
}
@Override
protected @NonNull CGParameterStyle @NonNull [] getCGParameterStyles(@NonNull ExecutableNameManager operationNameManager) {
Operation asOrigin = (Operation) operationNameManager.getASOrigin();
// LibraryFeature asImplementation = asOrigin.getImplementation();
LibraryOperation asImplementation = (LibraryOperation)operationNameManager.getCodeGenerator().getEnvironmentFactory().getMetamodelManager().getImplementation(asOrigin);
Method method = null;
boolean hasExecutor = false;
boolean hasTypeId = false;
int hasSelfThenArgs = 0;
if (asImplementation instanceof AbstractOperation) {
method = ((AbstractOperation)asImplementation).getEvaluateMethod(asOrigin);
for (Class<?> jParameterType : method.getParameterTypes()) {
if (jParameterType == Executor.class) {
assert !hasExecutor;
assert !hasTypeId;
assert hasSelfThenArgs == 0;
hasExecutor = true;
}
else if (jParameterType == TypeId.class) {
assert hasExecutor;
assert !hasTypeId;
assert hasSelfThenArgs == 0;
hasTypeId = true;
}
else {
hasSelfThenArgs++;
}
}
}
assert hasSelfThenArgs == (asOrigin.isIsStatic() ? 0 : 1) + asOrigin.getOwnedParameters().size();
/* if (hasTypeId) {
assert hasExecutor;
return CG_PARAMETER_STYLES_THIS_TYPE_ID_BOXED_VALUES;
}
// else if (hasExecutor) {
// return CG_PARAMETER_STYLES_THIS_EXECUTOR_BOXED_VALUES;
// }
else*/ {
return CG_PARAMETER_STYLES_THIS_BOXED_VALUES;
}
}
}
/**
* ExternalEntryClassCallingConvention refines the standard EntryClassCallingConvention for the cache of a specific evaluation
* to support a local class for an non-local facility.
*/
public static class ImplementedEntryClassCallingConvention extends ExternalEntryClassCallingConvention
{
private static final @NonNull ImplementedEntryClassCallingConvention INSTANCE = new ImplementedEntryClassCallingConvention();
public static @NonNull ImplementedEntryClassCallingConvention getInstance(@NonNull Operation asOperation) {
INSTANCE.logInstance(asOperation);
return INSTANCE;
}
@Override
protected void installConstructorOperation(@NonNull CodeGenAnalyzer analyzer, @NonNull CGClass cgEntryClass, @NonNull Operation asOperation) {
org.eclipse.ocl.pivot.Class asEntryClass = CGUtil.getAST(cgEntryClass);
AbstractConstructorOperationCallingConvention callingConvention = ImplementedConstructorOperationCallingConvention.getInstance(asEntryClass);
callingConvention.createOperation(analyzer, cgEntryClass, asOperation);
}
}
@Override
public void createCGBody(@NonNull CodeGenAnalyzer analyzer, @NonNull CGOperation cgOuterOperation) {
// direct synthesis
}
@Override
public @NonNull CGOperation createOperation(@NonNull CodeGenAnalyzer analyzer, @NonNull Operation asOperation, @Nullable ExpressionInOCL asExpressionInOCL) {// XXX cf super
// assert asOperation.getImplementationClass() == null;
CGOperation cgOperation = createCGOperation(analyzer, asOperation);
analyzer.initAst(cgOperation, asOperation, true);
CGClass cgRootClass = analyzer.getCGRootClass(asOperation);
cgRootClass.getOperations().add(cgOperation);
createCachingClassesAndInstance(analyzer, cgOperation);
cgOperation.setCallingConvention(this);
assert asOperation == cgOperation.getAst();
assert analyzer.basicGetCGElement(asOperation) != null;
ExecutableNameManager operationNameManager = analyzer.getOperationNameManager(cgOperation, asOperation, null); // Needed to support downstream useOperationNameManager()
assert cgOperation.eContainer() != null;
@NonNull CGParameterStyle @NonNull [] cgParameterStyles = getCGParameterStyles(operationNameManager);
operationNameManager.createCGOperationParameters(cgParameterStyles);
return cgOperation;
}
@Override
protected @NonNull AbstractEntryClassCallingConvention getEntryClassCallingConvention(@NonNull Operation asOperation) {
return ImplementedEntryClassCallingConvention.getInstance(asOperation);
}
}