blob: 37b375681ed5c9fcd4751ec98e120f0e5a3f7a03 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2018 CEA LIST 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(CEA LIST) - Initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.codegen.analyzer;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.cgmodel.CGBoolean;
import org.eclipse.ocl.examples.codegen.cgmodel.CGConstant;
import org.eclipse.ocl.examples.codegen.cgmodel.CGConstantExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElementId;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorOperation;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorProperty;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorShadowPart;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorType;
import org.eclipse.ocl.examples.codegen.cgmodel.CGInteger;
import org.eclipse.ocl.examples.codegen.cgmodel.CGInvalid;
import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory;
import org.eclipse.ocl.examples.codegen.cgmodel.CGNull;
import org.eclipse.ocl.examples.codegen.cgmodel.CGReal;
import org.eclipse.ocl.examples.codegen.cgmodel.CGString;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId;
import org.eclipse.ocl.examples.codegen.cgmodel.CGUnlimited;
import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement;
import org.eclipse.ocl.examples.codegen.generator.CodeGenerator;
import org.eclipse.ocl.examples.codegen.utilities.CGUtil;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.ids.ElementId;
import org.eclipse.ocl.pivot.ids.OperationId;
import org.eclipse.ocl.pivot.ids.PropertyId;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
/**
* A CodeGenAnalyzer performs the analysis of a Pivot AST in preparation for code generation.
* <p>
* Pass 1: AS2CGAnalysisVisitor
* <br>
* Each AS Element is converted to a CGElement
* <br>
* This conversion creates objects such as CGLibraryOperationCallEXp that are more atuned to CG
* and provides a tree that can be rewritten by optimizations.
* <p>
* Pass 2: CGPreAnalysisVisitor
* <br>
* Traversal of the CG containment tree performs
* <br>
* constant folding
* <p>
* <p>
* Pass N-2: CG2JavaPreVisitor
* <br>
* Traversal of the CG containment tree prepares for Java CG by
* <br>
* gathering imports
* <p>
* Pass N-1: CommonSubexpressionEliminator
* <br>
* Traversal of the CG tree to share common terms and remove dead code
* <p>
* Pass N: CG2JavaVisitor
* <br>
* Traversal of the CG containment tree emits code
*/
public class CodeGenAnalyzer
{
protected final @NonNull CodeGenerator codeGenerator;
protected final @NonNull NameManager nameManager;
private @NonNull Map<ElementId, CGElementId> cgElementIds = new HashMap<ElementId, CGElementId>();
protected final @NonNull CGBoolean cgFalse;
protected final @NonNull CGBoolean cgTrue;
private /*@LazyNonNull*/ CGUnlimited cgUnlimited = null;
private /*@LazyNonNull*/ CGInvalid cgInvalid = null;
protected final @NonNull CGNull cgNull;
private final @NonNull Map<Number, CGInteger> cgIntegers = new HashMap<Number, CGInteger>();
private final @NonNull Map<Number, CGReal> cgReals = new HashMap<Number, CGReal>();
private final @NonNull Map<String, CGString> cgStrings = new HashMap<String, CGString>();
public CodeGenAnalyzer(@NonNull CodeGenerator codeGenerator) {
this.codeGenerator = codeGenerator;
this.nameManager = codeGenerator.getNameManager();
cgFalse = createCGBoolean(false);
cgTrue = createCGBoolean(true);
cgNull = createCGNull();
}
public void analyze(@NonNull CGElement cgRoot) {
AnalysisVisitor analysisVisitor = codeGenerator.createAnalysisVisitor();
cgRoot.accept(analysisVisitor);
//
BoxingAnalyzer boxingAnalyzer = codeGenerator.createBoxingAnalyzer();
cgRoot.accept(boxingAnalyzer);
//
FieldingAnalyzer fieldingAnalyzer = codeGenerator.createFieldingAnalyzer();
fieldingAnalyzer.analyze(cgRoot, false);
}
public @NonNull CGValuedElement createCGConstantExp(@NonNull CGConstant cgConstant) {
CGConstantExp cgConstantExp = CGModelFactory.eINSTANCE.createCGConstantExp();
cgConstantExp.setAst(cgConstant.getAst());
cgConstantExp.setReferredConstant(cgConstant);
cgConstantExp.setTypeId(cgConstant.getTypeId());
return cgConstantExp;
}
public @NonNull CGConstantExp createCGConstantExp(@NonNull OCLExpression element, @NonNull CGConstant cgConstant) {
CGConstantExp cgConstantExp = CGModelFactory.eINSTANCE.createCGConstantExp();
cgConstantExp.setAst(element);
cgConstantExp.setReferredConstant(cgConstant);
cgConstantExp.setTypeId(getTypeId(element.getTypeId()));
return cgConstantExp;
}
protected @NonNull CGBoolean createCGBoolean(boolean booleanValue) {
CGBoolean cgBoolean = CGModelFactory.eINSTANCE.createCGBoolean();
setExplicitNames(cgBoolean, booleanValue);
cgBoolean.setBooleanValue(booleanValue);
cgBoolean.setTypeId(getTypeId(TypeId.BOOLEAN));
return cgBoolean;
}
protected @NonNull CGNull createCGNull() {
CGNull cgNull = CGModelFactory.eINSTANCE.createCGNull();
setExplicitNames(cgNull, null);
cgNull.setTypeId(getTypeId(TypeId.OCL_VOID));
return cgNull;
}
public @NonNull CGExecutorOperation createExecutorOperation(@NonNull Operation asOperation) {
OperationId operationId = asOperation.getOperationId();
CGExecutorOperation cgOperation = CGModelFactory.eINSTANCE.createCGExecutorOperation();
CGElementId cgOperationId = getElementId(operationId);
cgOperation.setTypeId(getTypeId(asOperation.getTypeId()));
cgOperation.setUnderlyingOperationId(cgOperationId);
cgOperation.setAst(asOperation);
cgOperation.setName(nameManager.getGlobalSymbolName(asOperation));
// cgOperation.setValueName(cgOperation.getName());
cgOperation.getDependsOn().add(cgOperationId);
return cgOperation;
}
public @NonNull CGExecutorProperty createExecutorOppositeProperty(@NonNull Property asProperty) {
PropertyId propertyId = asProperty.getPropertyId();
CGExecutorProperty cgProperty = null;
CGElementId cgPropertyId = getElementId(propertyId);
Property asOppositeProperty = ClassUtil.nonNullState(asProperty.getOpposite());
if (asOppositeProperty.isIsComposite()) {
cgPropertyId = getElementId(asOppositeProperty.getPropertyId());
cgProperty = CGModelFactory.eINSTANCE.createCGExecutorCompositionProperty();
cgProperty.setUnderlyingPropertyId(cgPropertyId);
cgProperty.setAst(asOppositeProperty);
cgProperty.setName("IMPPROPid_" + asOppositeProperty.getName());
cgProperty.getDependsOn().add(cgPropertyId);
}
else {
cgPropertyId = getElementId(asOppositeProperty.getPropertyId());
cgProperty = CGModelFactory.eINSTANCE.createCGExecutorOppositeProperty();
cgProperty.setUnderlyingPropertyId(cgPropertyId);
cgProperty.setAst(asProperty);
cgProperty.setName("IMPPROPid_" + asProperty.getName());
cgProperty.getDependsOn().add(cgPropertyId);
}
return cgProperty;
}
public @NonNull CGExecutorProperty createExecutorProperty(@NonNull Property asProperty) {
PropertyId propertyId = asProperty.getPropertyId();
CGElementId cgPropertyId = getElementId(propertyId);
CGExecutorProperty cgProperty = CGModelFactory.eINSTANCE.createCGExecutorNavigationProperty();
cgProperty.setUnderlyingPropertyId(cgPropertyId);
cgProperty.setAst(asProperty);
cgProperty.setName("IMPPROPid_" + asProperty.getName());
cgProperty.getDependsOn().add(cgPropertyId);
return cgProperty;
}
public @NonNull CGExecutorShadowPart createExecutorShadowPart(@NonNull Property asProperty) {
PropertyId propertyId = asProperty.getPropertyId();
CGExecutorShadowPart cgPart = CGModelFactory.eINSTANCE.createCGExecutorShadowPart();
CGElementId cgPropertyId = getElementId(propertyId);
cgPart.setUnderlyingPropertyId(cgPropertyId);
cgPart.setAst(asProperty);
cgPart.setName("CTORid_" + asProperty.getName());
cgPart.getDependsOn().add(cgPropertyId);
return cgPart;
}
public @NonNull CGExecutorType createExecutorType(@NonNull Type asType) {
TypeId typeId = asType.getTypeId();
CGExecutorType cgType = CGModelFactory.eINSTANCE.createCGExecutorType();
CGTypeId cgTypeId = getTypeId(typeId);
cgType.setUnderlyingTypeId(cgTypeId);
cgType.setAst(asType);
cgType.setName(getNameManager().getGlobalSymbolName(asType));
// cgType.setValueName(cgType.getName());
cgType.getDependsOn().add(cgTypeId);
return cgType;
}
public @NonNull CGBoolean getBoolean(boolean aBoolean) {
return aBoolean ? cgTrue : cgFalse;
}
public @NonNull CodeGenerator getCodeGenerator() {
return codeGenerator;
}
public @NonNull CGElementId getElementId(@NonNull ElementId elementId) {
CGElementId cgElementId = cgElementIds.get(elementId);
if (cgElementId == null) {
if (elementId instanceof TypeId) {
return getTypeId((TypeId)elementId);
}
cgElementId = CGModelFactory.eINSTANCE.createCGElementId();
cgElementId.setElementId(elementId);
setNames(cgElementId, elementId);
cgElementIds.put(elementId, cgElementId);
}
return cgElementId;
}
public @NonNull CGValuedElement getExpression(@Nullable CGValuedElement cgExpression) {
if (cgExpression == null) {
CGConstantExp cgLiteralExp = CGModelFactory.eINSTANCE.createCGConstantExp();
// cgLiteralExp.setAst(element);
cgLiteralExp.setReferredConstant(getInvalid());
cgLiteralExp.setTypeId(getTypeId(TypeId.OCL_INVALID));
cgExpression = cgLiteralExp;
};
return cgExpression;
}
public @NonNull CGInteger getInteger(@NonNull Number aNumber) {
CGInteger cgInteger = cgIntegers.get(aNumber);
if (cgInteger == null) {
cgInteger = CGModelFactory.eINSTANCE.createCGInteger();
setNames(cgInteger, aNumber);
cgInteger.setNumericValue(aNumber);
cgInteger.setTypeId(getTypeId(TypeId.INTEGER));
cgIntegers.put(aNumber, cgInteger);
}
return cgInteger;
}
public @NonNull CGInvalid getInvalid() {
CGInvalid cgInvalid2 = cgInvalid;
if (cgInvalid2 == null) {
cgInvalid = cgInvalid2 = CGModelFactory.eINSTANCE.createCGInvalid();
// cgInvalid.setAst(ValuesUtil.INVALID_VALUE);
setNames(cgInvalid2, ValueUtil.INVALID_VALUE);
cgInvalid2.setTypeId(getTypeId(TypeId.OCL_INVALID));
}
return cgInvalid2;
}
public @NonNull CGInvalid getInvalid(/*@NonNull*/ String messageTemplate, Object... bindings) {
CGInvalid cgInvalid = CGModelFactory.eINSTANCE.createCGInvalid();
setNames(cgInvalid, ValueUtil.INVALID_VALUE);
cgInvalid.setTypeId(getTypeId(TypeId.OCL_INVALID));
cgInvalid.setMessageTemplate(messageTemplate);
for (Object binding : bindings) {
cgInvalid.getBindings().add(binding);
}
return cgInvalid;
}
public @NonNull CGNull getNull() {
return cgNull;
}
public @NonNull CGReal getReal(@NonNull Number aNumber) {
CGReal cgReal = cgReals.get(aNumber);
if (cgReal == null) {
cgReal = CGModelFactory.eINSTANCE.createCGReal();
setNames(cgReal, aNumber);
cgReal.setNumericValue(aNumber);
cgReal.setTypeId(getTypeId(TypeId.REAL));
cgReals.put(aNumber, cgReal);
}
return cgReal;
}
public @NonNull CGString getString(@NonNull String aString) {
CGString cgString = cgStrings.get(aString);
if (cgString == null) {
cgString = CGModelFactory.eINSTANCE.createCGString();
setNames(cgString, aString);
cgString.setStringValue(aString);
cgString.setTypeId(getTypeId(TypeId.STRING));
cgStrings.put(aString, cgString);
}
return cgString;
}
public @NonNull NameManager getNameManager() {
return ClassUtil.nonNullState(nameManager);
}
public @NonNull CGTypeId getTypeId(@NonNull TypeId typeId) {
CGElementId cgElementId = cgElementIds.get(typeId);
CGTypeId cgTypeId = (CGTypeId)cgElementId;
if (cgTypeId == null) {
cgTypeId = CGModelFactory.eINSTANCE.createCGTypeId();
cgTypeId.setElementId(typeId);
cgTypeId.setName(nameManager.getGlobalSymbolName(typeId));
cgTypeId.setValueName(ClassUtil.nonNullState(cgTypeId.getName()));
cgElementIds.put(typeId, cgTypeId);
}
return cgTypeId;
}
public @NonNull CGUnlimited getUnlimited() {
CGUnlimited cgUnlimited2 = cgUnlimited;
if (cgUnlimited2 == null) {
cgUnlimited = cgUnlimited2 = CGModelFactory.eINSTANCE.createCGUnlimited();
setNames(cgUnlimited2, ValueUtil.UNLIMITED_VALUE);
cgUnlimited2.setTypeId(getTypeId(TypeId.UNLIMITED_NATURAL));
}
return cgUnlimited2;
}
/**
* Replace oldElement by newElement and return oldElement which is orphaned by the replacement.
*/
public @NonNull CGValuedElement replace(@NonNull CGValuedElement oldElement, @NonNull CGValuedElement newElement,
/*@NonNull*/ String messageTemplate, Object... bindings) {
if (oldElement.isRequired() && newElement.isNull()) {
newElement = getInvalid(messageTemplate, bindings);
}
return CGUtil.replace(oldElement, newElement);
}
public void setConstant(@NonNull CGValuedElement oldElement, @NonNull CGValuedElement aConstant) {
CGConstantExp newElement = CGModelFactory.eINSTANCE.createCGConstantExp(); // FIXME wrapper not needed
newElement.setReferredConstant(aConstant);
newElement.setTypeId(oldElement.getTypeId());
newElement.setAst(oldElement.getAst());
CGUtil.replace(oldElement, newElement);
}
public void setExplicitNames(@NonNull CGValuedElement cgValue, @Nullable Object anObject) {
String name = nameManager.getExplicitName(anObject);
cgValue.setName(name);
cgValue.setValueName(name);
}
public void setNames(@NonNull CGValuedElement cgValue, @NonNull Object anObject) {
String name = nameManager.getGlobalSymbolName(anObject);
cgValue.setName(name);
cgValue.setValueName(name);
}
}