blob: ff6fd957272a015585ff5b9713ac30761e52168c [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2020-2021 Robert Bosch GmbH.
*
* 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.slg.commons.m2t.transformers.sw;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.app4mc.amalthea.model.ActivityGraph;
import org.eclipse.app4mc.amalthea.model.ActivityGraphItem;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.StringObject;
import org.eclipse.app4mc.amalthea.model.Value;
import org.eclipse.app4mc.amalthea.model.impl.CustomPropertyImpl;
import org.eclipse.app4mc.slg.commons.m2t.CustomObjectsStore;
import org.eclipse.app4mc.slg.commons.m2t.generators.RunnableGenerator;
import org.eclipse.app4mc.slg.commons.m2t.transformers.SLGBaseTransformer;
import org.eclipse.app4mc.slg.commons.m2t.transformers.SLGTranslationUnit;
import org.eclipse.app4mc.slg.config.CodehookType;
import org.eclipse.app4mc.slg.config.ConfigModel;
import org.eclipse.app4mc.slg.config.util.ConfigModelUtils;
import org.eclipse.app4mc.transformation.util.OutputBuffer;
import org.eclipse.emf.ecore.EObject;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class RunnableTransformer extends SLGBaseTransformer {
@Inject private OutputBuffer outputBuffer;
@Inject private ActivityGraphItemTransformer activityGraphItemTransformer;
@Inject private CustomObjectsStore customObjsStore;
@Inject private Properties properties;
private static final String RUNNABLE_TITLE_START = "\n//Runnable ";
private static final String RUNNABLE_TITLE_END = "----\n";
private static final String VOID = "void ";
// ---------- generic part "def create new transform(...)" ----------
private final Map<List<Object>, SLGTranslationUnit> transformCache = new HashMap<>();
@Override
public Map<List<Object>, SLGTranslationUnit> getCache() {
return this.transformCache;
}
public SLGTranslationUnit transform(final Runnable runnable) {
final List<Object> key = new ArrayList<>(Arrays.asList(runnable));
final SLGTranslationUnit tu;
synchronized (transformCache) {
if (transformCache.containsKey(key)) {
return transformCache.get(key);
}
tu = createTranslationUnit(runnable);
transformCache.put(key, tu);
}
// if translation unit is newly created and valid -> create files
if (tu.isValid()) {
doTransform(tu, runnable);
}
return tu;
}
// ---------------------------------------------------
protected SLGTranslationUnit createTranslationUnit(final Runnable runnable) {
if ((runnable == null)) {
return new SLGTranslationUnit("UNSPECIFIED RUNNABLE");
} else {
String basePath = "synthetic_gen";
String moduleName = "runnables";
String call = "run_" + runnable.getName() + "()";
return new SLGTranslationUnit(basePath, moduleName, call);
}
}
protected void doTransform(final SLGTranslationUnit tu, final Runnable runnable) {
genFiles(tu, runnable);
}
protected void genFiles(final SLGTranslationUnit tu, final Runnable runnable) {
if (isSrcFileEmpty(tu)) {
srcAppend(tu, "#include \"" + getIncFile(tu) + "\"\n");
}
boolean extOverwrite = false;
final HashSet<String> includes = new LinkedHashSet<>();
final List<String> calls = new ArrayList<>();
final List<String> callsOverwrite = new ArrayList<>();
if (runnable != null && runnable.getActivityGraph() != null) {
extOverwrite = processCustomProperties(extOverwrite, calls, callsOverwrite, runnable.getActivityGraph());
for (ActivityGraphItem item : runnable.getActivityGraph().getItems()) {
final SLGTranslationUnit tmpTU = activityGraphItemTransformer.transform(item);
String tmpIncFile = getIncFile(tmpTU);
if (tmpIncFile != null && !tmpIncFile.isEmpty() && !tmpIncFile.equals(getIncFile(tu))) {
includes.add(tmpIncFile);
}
final String tmpCall = tmpTU.getCall();
if (tmpCall != null && !tmpCall.isEmpty()) {
calls.add(tmpCall);
}
}
}
incAppend(tu, RUNNABLE_TITLE_START + runnable.getName() + RUNNABLE_TITLE_END);
toH(tu,runnable.getName(), includes);
srcAppend(tu, RUNNABLE_TITLE_START + runnable.getName() + RUNNABLE_TITLE_END);
if (extOverwrite) {
srcAppend(tu, VOID + tu.getCall() + "{\n");
for (String call : callsOverwrite) {
srcAppend(tu, call + ";" + "\n");
}
srcAppend(tu, "\n" + "}" + "\n");
}
// ------------------------
else {
toCpp(tu, calls); // write body without overwriting the codehook function
}
}
protected boolean processCustomProperties(boolean extOverwrite, final List<String> calls,
final List<String> callsOverwrite, final ActivityGraph activityGraph) {
for (EObject item : activityGraph.eContents()) {
if (item instanceof CustomPropertyImpl) // custom property:
{
boolean enableExtCode = Boolean.parseBoolean(properties.getProperty("enableExternalCode"));
if (enableExtCode) {
if (((CustomPropertyImpl) item).getKey().equals("codehook")) {
Value value = ((CustomPropertyImpl) item).getValue();
if (value instanceof StringObject) {
calls.add(((StringObject) value).getValue());
}
} else if (((CustomPropertyImpl) item).getKey().equals("codehook_overwrite")) {
extOverwrite = true;
Value value1 = ((CustomPropertyImpl) item).getValue();
if (value1 instanceof StringObject) {
callsOverwrite.add(((StringObject) value1).getValue());
}
}
}
}
}
return extOverwrite;
}
protected void toH(final SLGTranslationUnit tu, final String runnableName, final HashSet<String> includes) {
if (isIncFileEmpty(tu)) {
final ConfigModel configModel = customObjsStore.<ConfigModel>getInstance(ConfigModel.class);
boolean enableExtCode = Boolean.parseBoolean(properties.getProperty("enableExternalCode"));
if (enableExtCode) {
// fetching the names of the external codehook files
for (String hDir : ConfigModelUtils.getHeaderFilesDirectories(configModel, CodehookType.RUNNABLE)) {
final File folder = new File(hDir.trim()); // fetching all the names in the headerfile directory.
String names = ConfigModelUtils.getHeaderFilesIncludeMultiString(folder);
incAppend(tu, names);
}
}
incAppend(tu, "#include <string.h>\n");
for (String include : includes) {
incAppend(tu, "#include \"" + include + "\"\n");
}
}
incAppend(tu, RUNNABLE_TITLE_START + runnableName + RUNNABLE_TITLE_END);
incAppend(tu, VOID + tu.getCall() + "(char* coreName);\n");
}
/*
* protected void toH(final SLGTranslationUnit tu, final HashSet<String>
* includes) { for (String include : includes) { incAppend(tu, "#include \"" +
* include + "\"\n"); }
*
* incAppend(tu, "void " + tu.getCall() + ";\n"); }
*/
protected void toCpp(final SLGTranslationUnit tu, final List<String> calls) {
srcAppend(tu, VOID + tu.getCall() + "{\n");
for (String call : calls) {
srcAppend(tu, "\t" + call + ";\n");
}
srcAppend(tu, "}\n\n");
}
public boolean createCMake() {
// Building rule: basePath + moduleName + "CMakeLists.txt"
String makeFilePath = "synthetic_gen/runnables/CMakeLists.txt";
return outputBuffer.appendTo("OTHER", makeFilePath, RunnableGenerator.toCMake(getSrcFiles()));
}
}