blob: 8634b9b46b14a6bdf99934073cfbac49ba837acc [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2017 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.sca2amalthea.exporter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.app4mc.amalthea.model.Amalthea;
import org.eclipse.app4mc.amalthea.model.AmaltheaFactory;
import org.eclipse.app4mc.amalthea.model.CallGraph;
import org.eclipse.app4mc.amalthea.model.CallSequence;
import org.eclipse.app4mc.amalthea.model.ISR;
import org.eclipse.app4mc.amalthea.model.LabelAccessEnum;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.SWModel;
import org.eclipse.app4mc.amalthea.model.Semaphore;
import org.eclipse.app4mc.amalthea.model.SemaphoreAccess;
import org.eclipse.app4mc.amalthea.model.SemaphoreAccessEnum;
import org.eclipse.app4mc.amalthea.model.StringObject;
import org.eclipse.app4mc.amalthea.model.Task;
import org.eclipse.app4mc.amalthea.model.TaskRunnableCall;
import org.eclipse.app4mc.sca.logging.manager.LogFactory.Severity;
import org.eclipse.app4mc.sca.logging.util.LogUtil;
import org.eclipse.app4mc.sca2amalthea.exporter.locks.LockFunction.LockType;
import org.eclipse.app4mc.sca2amalthea.exporter.util.CustomPropertiesAdder;
import org.eclipse.app4mc.sca2amalthea.exporter.util.LLVMLogUtil;
import org.eclipse.app4mc.sca2amalthea.ir.scair.Container;
import org.eclipse.app4mc.sca2amalthea.ir.scair.EFunctionTypeEnum;
import org.eclipse.app4mc.sca2amalthea.ir.scair.Function;
import org.eclipse.app4mc.sca2amalthea.ir.scair.FunctionCall;
import org.eclipse.app4mc.sca2amalthea.ir.scair.Label;
import org.eclipse.app4mc.sca2amalthea.ir.scair.LabelAccess;
import org.eclipse.app4mc.sca2amalthea.ir.scair.Project;
import org.eclipse.app4mc.sca2amalthea.ir.scair.StmtCall;
import org.eclipse.app4mc.sca2amalthea.serialization.SCAResource;
import org.eclipse.emf.common.util.EList;
/**
* This class transforms all SwModel related part and submodels to the AMALTHEA model
*/
public class SwModelTransformer {
private final TransformerDataStore data;
private final ComponentModelTransformer componentTransformer;
private final SwModelTypeDefTransformer typeExporter = new SwModelTypeDefTransformer();
/**
* @param dataStore
* @param componentTransformer
*/
public SwModelTransformer(final TransformerDataStore dataStore,
final ComponentModelTransformer componentTransformer) {
super();
this.data = dataStore;
this.componentTransformer = componentTransformer;
}
/**
* @param amaltheaModel resulting AMALTHEA model
* @param resource SCAIR to be transformed
*/
public void transform(final Amalthea amaltheaModel, final SCAResource resource) {
SWModel swModel = AmaltheaFactory.eINSTANCE.createSWModel();
amaltheaModel.setSwModel(swModel);
this.typeExporter.transform(resource, swModel);
transformLabels(resource, swModel);
Set<Function> allFunctions = getAllfunctions(resource);
Set<Function> ignoreList = prepareIgnoreList(allFunctions);
allFunctions.removeAll(ignoreList);
EList<Runnable> runnables = swModel.getRunnables();
EList<Task> tasks = swModel.getTasks();
EList<ISR> isrs = swModel.getIsrs();
transformFirstLevel(allFunctions, runnables, tasks, isrs);
for (Function func : allFunctions) {
try {
if (func.getType().getLiteral().equalsIgnoreCase(EFunctionTypeEnum.RUNNABLE.getLiteral())) {
transformRunnableInternals(func);
}
else if (func.getType().getLiteral().equalsIgnoreCase(EFunctionTypeEnum.TASK.getLiteral())) {
transformTaskInternals(func);
}
else if (func.getType().getLiteral().equalsIgnoreCase(EFunctionTypeEnum.ISR.getLiteral())) {
transformISRInternals(func);
}
}
catch (Exception e) {
LogUtil.log(LLVMLogUtil.LOG_MSG_ID, Severity.DEBUG, "**Function transformation problem" + func.getName(),
this.getClass(), Activator.PLUGIN_ID);
LogUtil.logException(LLVMLogUtil.LOG_MSG_ID, e.getClass(), e, Activator.PLUGIN_ID);
}
}
}
/**
* @param resource
* @param swModel
*/
private void transformLabels(final SCAResource resource, final SWModel swModel) {
EList<Label> labels = ((Project) resource.getContents().get(0)).getLabels();
EList<org.eclipse.app4mc.amalthea.model.Label> amlabels = swModel.getLabels();
for (Label label : labels) {
org.eclipse.app4mc.amalthea.model.Label amaltheaLabel = AmaltheaFactory.eINSTANCE.createLabel();
amaltheaLabel.setName(label.getName());
this.data.getLabelMap().put(label.getName(), amaltheaLabel);
CustomPropertiesAdder.addFilePackageInformation(amaltheaLabel, label.getFile(), label.getPackage());
amlabels.add(amaltheaLabel);
this.typeExporter.transformTypeDefitionToLabel(amaltheaLabel, label);
}
}
/**
* This function collects all functions which should not be transformed as runnables because either they are semaphore
* calls or included in a semaphore function
*
* @param allFunctions
* @return
*/
private Set<Function> prepareIgnoreList(final Set<Function> allFunctions) {
Set<String> keySet = this.data.getSemaMap().keySet();
Set<Function> ignorelist = new HashSet<Function>();
for (Function f : allFunctions) {
if (keySet.contains(f.getName())) {
ignorelist.add(f);
ignorelist.addAll(extractCalledFunctions(f));
}
}
return ignorelist;
}
/**
* This function collects the function calls from statements sequence of {@link function}
*/
private List<Function> extractCalledFunctions(final Function function) {
List<Function> calls = (function.getStmtseq()).stream().filter(stmt -> stmt instanceof FunctionCall)
.map(stmt -> ((FunctionCall) stmt).getCalls()).collect(Collectors.toList());
List<Function> calledinCalls = new ArrayList<Function>();
for (Function f : calls) {
calledinCalls.addAll(extractCalledFunctions(f));
}
calls.addAll(calledinCalls);
return calls;
}
/**
* @param containers
* @return
*/
private Set<Function> getAllfunctions(final SCAResource resource) {
EList<Container> containers = ((Project) resource.getContents().get(0)).getContainers();
Set<Function> allFunctions = new HashSet<Function>();
for (Container c : containers) {
allFunctions.addAll(c.getFunctions());
}
return allFunctions;
}
/**
* @param function
*/
private void transformISRInternals(final Function function) {
String name = function.getName();
ISR isr = this.data.getIsrMap().get(name);
CallGraph callGraph = AmaltheaFactory.eINSTANCE.createCallGraph();
CallSequence callSequence = AmaltheaFactory.eINSTANCE.createCallSequence();
transformStatements(function, callGraph, callSequence);
isr.setCallGraph(callGraph);
}
/**
* @param runnablesMap
* @param function
* @param callGraph
* @param callSequence
*/
private void transformStatements(final Function function, final CallGraph callGraph,
final CallSequence callSequence) {
EList<StmtCall> stmtseq = function.getStmtseq();
for (StmtCall stmtCall : stmtseq) {
if (stmtCall instanceof FunctionCall) {
FunctionCall fc = (FunctionCall) stmtCall;
Runnable runnable = this.data.getRunnableMap().get(fc.getCalls().getName());
if (runnable != null) {
TaskRunnableCall taskRunnableCall = AmaltheaFactory.eINSTANCE.createTaskRunnableCall();
taskRunnableCall.setRunnable(runnable);
callSequence.getCalls().add(taskRunnableCall);
CustomPropertiesAdder.addSourceLineInformation(taskRunnableCall, fc.getSrcline(), fc.getSrccol());
}
}
}
callGraph.getGraphEntries().add(callSequence);
}
/**
* @param function
*/
private void transformTaskInternals(final Function function) {
String name = function.getName();
Task task = this.data.getTaskMap().get(name);
CallGraph callGraph = AmaltheaFactory.eINSTANCE.createCallGraph();
CallSequence callSequence = AmaltheaFactory.eINSTANCE.createCallSequence();
transformStatements(function, callGraph, callSequence);
task.setCallGraph(callGraph);
}
/**
* @param runnables
* @param labelsMap
* @param runnablesMap
* @param function
* @param calls
* @param fname
*/
private void transformRunnableInternals(final Function function) {
String name = function.getName();
Runnable runnable = this.data.getRunnableMap().get(name);
EList<StmtCall> stmtseq = function.getStmtseq();
for (StmtCall stmtCall : stmtseq) {
if (stmtCall instanceof FunctionCall) {
FunctionCall fc = (FunctionCall) stmtCall;
String calledFunc = fc.getCalls().getName();
if (this.data.getSemaMap().keySet().contains(fc.getCalls().getName())) {
String srcLine = fc.getSrcline();
String srcCol = fc.getSrccol();
checkForSemaphoreCall(runnable, calledFunc, srcLine, srcCol);
}
else {
handleRunnableCall(name, runnable, fc);
}
}
else if (stmtCall instanceof LabelAccess) {
handleLabelAccess(runnable, stmtCall);
}
}
}
/**
* @param name
* @param runnable
* @param fc
*/
private void handleRunnableCall(final String name, final Runnable runnable, final FunctionCall fc) {
String calledFunc = fc.getCalls().getName();
Runnable calledRunnable = this.data.getRunnableMap().get(calledFunc);
if (calledRunnable != null) {
org.eclipse.app4mc.amalthea.model.RunnableCall runnableCall = AmaltheaFactory.eINSTANCE.createRunnableCall();
runnableCall.setRunnable(calledRunnable);
runnable.getRunnableItems().add(runnableCall);
CustomPropertiesAdder.addSourceLineInformation(runnableCall, fc.getSrcline(), fc.getSrccol());
}
else {
LogUtil.log(
LLVMLogUtil.LOG_MSG_ID, Severity.DEBUG, "Called Runnable do not exist for ***" + calledFunc + "*** in *" +
name + "*Possibly it appeared in ignored hierarchy of Lock Functions",
this.getClass(), Activator.PLUGIN_ID);
}
}
/**
* transform SCAIR labelAccess to AMALTHEA Label Access in a runnable
*
* @param runnable
* @param stmtCall
*/
private void handleLabelAccess(final Runnable runnable, final StmtCall stmtCall) {
LabelAccess labelAccess = (LabelAccess) stmtCall;
org.eclipse.app4mc.amalthea.model.LabelAccess amLabelAccess = AmaltheaFactory.eINSTANCE.createLabelAccess();
if ((labelAccess != null) && (labelAccess.getLabel() != null)) {
amLabelAccess.setData(this.data.getLabelMap().get(labelAccess.getLabel().getName()));
if ("Read".equalsIgnoreCase(labelAccess.getAccess().getLiteral())) {
amLabelAccess.setAccess(LabelAccessEnum.READ);
}
else {
amLabelAccess.setAccess(LabelAccessEnum.WRITE);
}
CustomPropertiesAdder.addSourceLineInformation(amLabelAccess, labelAccess.getSrcline(), labelAccess.getSrccol());
runnable.getRunnableItems().add(amLabelAccess);
}
else {
LogUtil.log(LLVMLogUtil.LOG_MSG_ID, Severity.DEBUG,
"**LabelAccess transformation problem in function " + runnable.getName(), this.getClass(),
Activator.PLUGIN_ID);
}
}
/**
* @param runnable
* @param calledFunc
*/
private void checkForSemaphoreCall(final Runnable runnable, final String calledFunc, final String srcLine,
final String srcCol) {
Semaphore semaphore = this.data.getSemaMap().get(calledFunc);
SemaphoreAccess semaAcc = AmaltheaFactory.eINSTANCE.createSemaphoreAccess();
if (((StringObject) semaphore.getCustomProperties().get(CustomPropertiesAdder.GET_LOCK_FUNC_NAME)).getValue()
.equalsIgnoreCase(calledFunc)) {
if (((StringObject) semaphore.getCustomProperties().get(CustomPropertiesAdder.LOCK_TYPE)).getValue()
.equalsIgnoreCase(LockType.EXCLUSIVE_LOCK.name())) {
semaAcc.setAccess(SemaphoreAccessEnum.EXCLUSIVE);
}
else {
semaAcc.setAccess(SemaphoreAccessEnum.REQUEST);
}
}
else if (((StringObject) semaphore.getCustomProperties().get(CustomPropertiesAdder.RELEASE_LOCK_FUNC_NAME))
.getValue().equalsIgnoreCase(calledFunc)) {
semaAcc.setAccess(SemaphoreAccessEnum.RELEASE);
}
semaAcc.setSemaphore(semaphore);
CustomPropertiesAdder.addSourceLineInformation(semaAcc, srcLine, srcCol);
runnable.getRunnableItems().add(semaAcc);
}
/**
* @param allFunctions
* @param runnables
* @param tasks
* @param isrs
*/
private void transformFirstLevel(final Set<Function> allFunctions, final EList<Runnable> runnables,
final EList<Task> tasks, final EList<ISR> isrs) {
for (Function function : allFunctions) {
switch (function.getType().getValue()) {
case EFunctionTypeEnum.ISR_VALUE:
createISR(function, isrs);
break;
case EFunctionTypeEnum.TASK_VALUE:
createTask(function, tasks);
break;
case EFunctionTypeEnum.RUNNABLE_VALUE:
createRunnable(function, runnables);
break;
default:
break;
}
}
}
/**
* This function creates the Task and also initializes the global {@link #data.getRunnableMap()}
*
* @param function
* @param runnables
*/
private void createRunnable(final Function function, final EList<Runnable> runnables) {
String fname = function.getName();
if (this.data.getRunnableMap().get(fname) != null) {
LogUtil.log(LLVMLogUtil.LOG_MSG_ID, Severity.DEBUG, "Duplicate function definition:" + fname, this.getClass(),
Activator.PLUGIN_ID);
}
if (this.data.getLabelMap().get(fname) != null) {
LogUtil.log(LLVMLogUtil.LOG_MSG_ID, Severity.DEBUG, "Function name is already defined as label:" + fname,
this.getClass(), Activator.PLUGIN_ID);
}
Runnable r = AmaltheaFactory.eINSTANCE.createRunnable();
r.setName(fname);
this.data.getRunnableMap().put(fname, r);
CustomPropertiesAdder.addSourceLineInformation(r, function.getSrcline(), function.getSrccol());
CustomPropertiesAdder.addFilePackageInformation(r, function.getFile(), function.getPackage());
this.componentTransformer.addRunnableToComponent(function, r);
runnables.add(r);
}
/**
* This function creates the Task and also initializes the global {@link #data.getTaskMap()}
*
* @param function
* @param tasks
*/
private void createTask(final Function function, final EList<Task> tasks) {
String fname = function.getName();
Task task = AmaltheaFactory.eINSTANCE.createTask();
task.setName(fname);
this.data.getTaskMap().put(fname, task);
CustomPropertiesAdder.addSourceLineInformation(task, function.getSrcline(), function.getSrccol());
this.componentTransformer.addTaskToComponent(function, task);
tasks.add(task);
}
/**
* This function creates the ISR and also initializes the global {@link #data.getIsrMap()}
*
* @param function
* @param isrs
*/
private void createISR(final Function function, final EList<ISR> isrs) {
String fname = function.getName();
ISR isr = AmaltheaFactory.eINSTANCE.createISR();
isr.setName(fname);
this.data.getIsrMap().put(fname, isr);
CustomPropertiesAdder.addSourceLineInformation(isr, function.getSrcline(), function.getSrccol());
this.componentTransformer.addTaskToComponent(function, isr);
isrs.add(isr);
}
}