blob: 29a21c95312a65ce30da927d789aa49949d809c6 [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.cs2as.compiler.internal;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.analyzer.AnalysisVisitor;
import org.eclipse.ocl.examples.codegen.analyzer.BoxingAnalyzer;
import org.eclipse.ocl.examples.codegen.analyzer.DependencyVisitor;
import org.eclipse.ocl.examples.codegen.analyzer.FieldingAnalyzer;
import org.eclipse.ocl.examples.codegen.analyzer.ReferencesVisitor;
import org.eclipse.ocl.examples.codegen.cgmodel.CGCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGGuardExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGPackage;
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.cse.GlobalPlace;
import org.eclipse.ocl.examples.codegen.dynamic.OCL2JavaFileObject;
import org.eclipse.ocl.examples.codegen.generator.TypeDescriptor;
import org.eclipse.ocl.examples.codegen.java.CG2JavaPreVisitor;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.Parameter;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.codegen.qvti.QVTiCodeGenOptions;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiAS2CGVisitor;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiAnalysisVisitor;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiAnalyzer;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiBoxingAnalyzer;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiDependencyVisitor;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiFieldingAnalyzer;
import org.eclipse.qvtd.codegen.qvti.analyzer.QVTiReferencesVisitor;
import org.eclipse.qvtd.codegen.qvti.java.QVTiCG2JavaPreVisitor;
import org.eclipse.qvtd.codegen.qvti.java.QVTiCG2JavaVisitor;
import org.eclipse.qvtd.codegen.qvti.java.QVTiCodeGenerator;
import org.eclipse.qvtd.codegen.qvti.java.QVTiGlobalContext;
import org.eclipse.qvtd.codegen.qvticgmodel.CGGuardVariable;
import org.eclipse.qvtd.codegen.qvticgmodel.CGMapping;
import org.eclipse.qvtd.codegen.utilities.QVTiCGUtil;
import org.eclipse.qvtd.cs2as.compiler.CS2ASJavaCompiler;
import org.eclipse.qvtd.cs2as.compiler.CS2ASJavaCompilerParameters;
import org.eclipse.qvtd.cs2as.compiler.cgmodel.CGLookupCallExp;
import org.eclipse.qvtd.cs2as.compiler.cgmodel.CS2ASCGFactory;
import org.eclipse.qvtd.cs2as.compiler.cgmodel.util.CS2ASCGModelVisitor;
import org.eclipse.qvtd.cs2as.runtime.CS2ASTransformation;
import org.eclipse.qvtd.cs2as.runtime.CS2ASTransformationExecutor;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtbase.evaluation.AbstractTransformationExecutor;
import org.eclipse.qvtd.pivot.qvtimperative.evaluation.QVTiEnvironmentFactory;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperative;
public class CS2ASJavaCompilerImpl implements CS2ASJavaCompiler {
protected static class CS2ASJavaCodeGenerator extends QVTiCodeGenerator
{
private @NonNull CS2ASJavaCompilerParameters params;
protected CS2ASJavaCodeGenerator(@NonNull QVTiEnvironmentFactory environmentFactory, @NonNull Transformation transformation,
@NonNull CS2ASJavaCompilerParameters params) {
super(environmentFactory, transformation);
this.params = params;
}
@Override
protected @NonNull QVTiCG2JavaVisitor createCG2JavaVisitor(@NonNull CGPackage cgPackage, @Nullable List<CGValuedElement> sortedGlobals) {
return new CS2ASCG2JavaVisitor(this, cgPackage, sortedGlobals);
}
@Override
protected @NonNull QVTiAS2CGVisitor createAS2CGVisitor(@NonNull QVTiAnalyzer analyzer,
@NonNull QVTiGlobalContext gContext) {
return new CS2ASAS2CGVisitor(analyzer, gContext);
}
@Override
public @NonNull AnalysisVisitor createAnalysisVisitor() {
return new CS2ASAnalysisVisitor(cgAnalyzer);
}
@Override
public @NonNull BoxingAnalyzer createBoxingAnalyzer() {
return new CS2ASBoxingAnalyser(cgAnalyzer);
}
@Override
public @NonNull FieldingAnalyzer createFieldingAnalyzer() {
return new CS2ASFieldingAnalyser(cgAnalyzer);
}
@Override
public @NonNull CG2JavaPreVisitor createCG2JavaPreVisitor() {
return new CS2ASCG2JavaPreVisitor(getGlobalContext());
}
@Override
public @NonNull ReferencesVisitor createReferencesVisitor() {
return CS2ASReferencesVisitor.INSTANCE;
}
@Override
public @NonNull DependencyVisitor createDependencyVisitor() {
return new CS2ASDependencyVisitor(cgAnalyzer, getGlobalContext(),
getGlobalPlace());
}
public @NonNull CS2ASJavaCompilerParameters getCGParameters() {
return params;
}
}
protected static class CS2ASCG2JavaVisitor extends QVTiCG2JavaVisitor implements CS2ASCGModelVisitor<Boolean>
{
protected CS2ASCG2JavaVisitor(@NonNull QVTiCodeGenerator codeGenerator, @NonNull CGPackage cgPackage, @Nullable List<CGValuedElement> sortedGlobals) {
super(codeGenerator, cgPackage, sortedGlobals);
}
@Override
protected void appendGuardFailure(@NonNull CGGuardExp cgGuardExp) {
CGMapping cgMapping = QVTiCGUtil.getContainingCGMapping(cgGuardExp);
if (cgMapping != null) {
List<CGGuardVariable> freeVariables = cgMapping.getFreeVariables();
if (freeVariables.size() > 0) {
CGGuardVariable cgGuardVariable = freeVariables.get(0);
js.append("throwNull(");
js.appendValueName(cgGuardVariable);
js.append(", ");
js.appendString("Null " + cgGuardExp.getMessage());
js.append(");\n");
return;
}
}
// CGUtil.createCGParameter(name, typeId)
super.appendGuardFailure(cgGuardExp);
}
protected @NonNull Class<? extends AbstractTransformationExecutor> getAbstractTransformationExecutorClass() {
return CS2ASTransformationExecutor.class;
}
@Override
@Nullable
public Boolean visitCGLookupCallExp(CGLookupCallExp cgCall) {
CS2ASJavaCompilerParameters params = ((CS2ASJavaCodeGenerator)getCodeGenerator()).getCGParameters();
CGValuedElement cgSource = cgCall.getSource(); // FIXME to skip env() call. Remove env() call
TypeDescriptor typeDescriptor = context.getTypeDescriptor(cgCall);
if (!js.appendLocalStatements(cgSource)) {
return false;
}
List<CGValuedElement> cgArguments = cgCall.getArguments();
for (@NonNull CGValuedElement cgArgument : cgArguments) {
CGValuedElement argument = getExpression(cgArgument);
if (!js.appendLocalStatements(argument)) {
return false;
}
}
String envClassName = params.getEnviromentClassName();
String envClassSymbol = getSymbolName(envClassName + cgCall.hashCode(), "_lookupEnv");
js.appendClassReference(envClassName);
js.append(" ");
js.append(envClassSymbol);
js.append(" = new ");
js.append(envClassName);
js.append("(evaluator,");
List<Parameter> pParameters = cgCall.getReferredOperation().getOwnedParameters();
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);
Parameter pParameter = pParameters.get(i);
CGTypeId cgTypeId = analyzer.getTypeId(pParameter.getTypeId());
TypeDescriptor parameterTypeDescriptor = context.getUnboxedDescriptor(ClassUtil.nonNullState(cgTypeId.getElementId()));
CGValuedElement argument = getExpression(cgArgument);
js.appendReferenceTo(parameterTypeDescriptor, argument);
}
js.append(");\n");
String visitorClassName = params.getVisitorClassName();
String visitorClassSymbol = getSymbolName(visitorClassName + cgCall.hashCode(), "_lookupVisitor");
js.appendClassReference(visitorClassName);
js.append(" ");
js.append(visitorClassSymbol);
js.append(" = new ");
js.append(params.getVisitorClassName());
js.append("(");
js.append(envClassSymbol);
js.append(");\n");
// FIXME what if there is not common named element class name ?
String namedElemClassName = params.getNamedElementClassName();
String resultSymbol = getSymbolName(namedElemClassName + cgCall.hashCode(), "_lookupResult");
js.appendClassReference(EList.class, false, namedElemClassName);
js.append(" ");
js.append(resultSymbol);
js.append(" = ");
js.appendReferenceTo(cgSource);
js.append(".accept(");
js.append(visitorClassSymbol);
js.append(").getNamedElements();\n");
js.appendClassReference(typeDescriptor);
js.append(" ");
js.appendReferenceTo(cgCall);
js.append( " = null;\n");
js.append("if ("+resultSymbol+".size() == 1) {\n");
js.pushIndentation(null);
js.appendReferenceTo(cgCall);
js.append(" = (");
js.appendClassReference(typeDescriptor);
js.append(")");
js.append(resultSymbol+".get(0);\n");
js.popIndentation();
// TODO what about ambigous error report ?
js.append("} else {\n");
js.pushIndentation(null);
CGValuedElement lookupArg = cgArguments.get(0); // FIXMe improve handleLookupError
CGValuedElement initialSource = initialSourceCG(lookupArg);
js.append("handleLookupError(");
js.appendReferenceTo(initialSource);
js.append(",");
js.appendReferenceTo(lookupArg);
js.append(");\n");
js.popIndentation();
js.append("};\n");
return true;
}
/**
* @param cgValue
* @return helper to obtain the initial CGValuedElement corresponding to the source of the lookupCall argument
*/
private CGValuedElement initialSourceCG(CGValuedElement cgValue) {
if (cgValue instanceof CGVariableExp) {
CGValuedElement cgVarInit = ((CGVariableExp) cgValue).getReferredVariable().getInit();
if (cgVarInit == null) {
return cgValue;
} else {
return cgVarInit == cgValue ? cgVarInit : initialSourceCG(cgVarInit);
}
} else if (cgValue instanceof CGCallExp) {
CGValuedElement cgSource = ((CGCallExp) cgValue).getSource();
return initialSourceCG(cgSource);
}
return cgValue;
}
}
protected static class CS2ASAS2CGVisitor extends QVTiAS2CGVisitor {
public CS2ASAS2CGVisitor(QVTiAnalyzer analyzer, QVTiGlobalContext globalContext) {
super(analyzer, globalContext);
}
@Override
protected @NonNull CGValuedElement generateOperationCallExp(@Nullable CGValuedElement cgSource, @NonNull OperationCallExp asOperationCallExp) {
Operation asOperation = asOperationCallExp.getReferredOperation();
if (isLookupOp(asOperation)) {
CGLookupCallExp cgLookupCallExp = CS2ASCGFactory.eINSTANCE.createCGLookupCallExp();
setAst(cgLookupCallExp, asOperationCallExp);
cgLookupCallExp.setSource(cgSource);
for (OCLExpression arg : asOperationCallExp.getOwnedArguments()) {
CGValuedElement cgArg = doVisit(CGValuedElement.class, arg);
cgLookupCallExp.getArguments().add(cgArg);
}
cgLookupCallExp.setReferredOperation(asOperation);
return cgLookupCallExp;
}
return super.generateOperationCallExp(cgSource, asOperationCallExp);
}
protected boolean isLookupOp(Operation op) {
String opName = op.getName();
if (opName != null && opName.startsWith("_lookup")) {// FIXME
return true;
}
return false;
}
}
protected static class CS2ASAnalysisVisitor extends QVTiAnalysisVisitor
implements CS2ASCGModelVisitor<Object> {
public CS2ASAnalysisVisitor(QVTiAnalyzer analyzer) {
super(analyzer);
}
@Override
@Nullable
public Object visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
protected static class CS2ASBoxingAnalyser extends QVTiBoxingAnalyzer
implements CS2ASCGModelVisitor<Object> {
public CS2ASBoxingAnalyser(QVTiAnalyzer analyzer) {
super(analyzer);
}
@Override
@Nullable
public Object visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
protected static class CS2ASFieldingAnalyser extends QVTiFieldingAnalyzer {
protected static class CS2ASAnalysisVisitor extends QVTiFieldingAnalyzer.QVTiAnalysisVisitor
implements CS2ASCGModelVisitor<Set<CGVariable>> {
public CS2ASAnalysisVisitor(QVTiFieldingAnalyzer context) {
super(context);
}
@Override
@Nullable
public Set<CGVariable> visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
protected static class CS2ASRewriteVisitor extends QVTiFieldingAnalyzer.QVTiRewriteVisitor
implements CS2ASCGModelVisitor<Boolean> {
public CS2ASRewriteVisitor(@NonNull QVTiAnalyzer context, @NonNull Set<CGVariable> caughtVariable) {
super(context, caughtVariable);
}
@Override
@Nullable
public Boolean visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
public CS2ASFieldingAnalyser(QVTiAnalyzer analyzer) {
super(analyzer);
}
@Override
protected @NonNull AnalysisVisitor createAnalysisVisitor() {
return new CS2ASAnalysisVisitor(this);
}
@Override
protected @NonNull RewriteVisitor createRewriteVisitor(@NonNull Set<CGVariable> caughtVariables) {
return new CS2ASRewriteVisitor((QVTiAnalyzer)analyzer, caughtVariables);
}
}
protected static class CS2ASCG2JavaPreVisitor extends QVTiCG2JavaPreVisitor
implements CS2ASCGModelVisitor<Object> {
public CS2ASCG2JavaPreVisitor(QVTiGlobalContext globalContext) {
super(globalContext);
}
@Override
@Nullable
public Object visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
protected static class CS2ASReferencesVisitor extends QVTiReferencesVisitor
implements CS2ASCGModelVisitor<List<Object>> {
protected static CS2ASReferencesVisitor INSTANCE = new CS2ASReferencesVisitor(new Object());
public CS2ASReferencesVisitor(Object context) {
super(context);
}
@Override
@Nullable
public List<Object> visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
protected static class CS2ASDependencyVisitor extends QVTiDependencyVisitor
implements CS2ASCGModelVisitor<Object> {
public CS2ASDependencyVisitor(QVTiAnalyzer analyzer, QVTiGlobalContext globalContext, GlobalPlace globalPlace) {
super(analyzer, globalContext, globalPlace);
}
@Override
@Nullable
public Object visitCGLookupCallExp(CGLookupCallExp object) {
return visitCGOperationCallExp(object);
}
}
// Copied from QVTiCompilerTest
@SuppressWarnings("unchecked")
protected Class<? extends CS2ASTransformation> compileTransformation(@NonNull QVTiCodeGenerator cg) throws Exception {
String qualifiedName = cg.getQualifiedName();
String javaCodeSource = cg.generateClassFile();
Class<?> txClass = OCL2JavaFileObject.loadClass(qualifiedName, javaCodeSource);
return (Class<? extends CS2ASTransformation>) txClass;
}
// Copied from QVTiCompilerTest
@Override
public Class<? extends CS2ASTransformation> compileTransformation(@NonNull QVTimperative qvt,
@NonNull Transformation transformation, @NonNull CS2ASJavaCompilerParameters params) throws Exception {
QVTiCodeGenerator cg = new CS2ASJavaCodeGenerator(qvt.getEnvironmentFactory(), transformation, params);
QVTiCodeGenOptions options = cg.getOptions();
options.setPackagePrefix(params.getPackageName());
cg.generateClassFile();
String savePath = params.getSavePath();
if (savePath != null) {
cg.saveSourceFile(savePath);
}
return compileTransformation(cg);
}
}