CppGenerator.xtend 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. package be.uantwerpen.ansymo.semanticadaptation.cg.cpp.generation
  2. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.GlobalInOutVariable
  3. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.IORuleType
  4. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.InOutRulesBlockResult
  5. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.InnerFMUData
  6. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.MappedScalarVariable
  7. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SAScalarVariable
  8. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SVCausality
  9. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.SVType
  10. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.data.ScalarVariable
  11. import be.uantwerpen.ansymo.semanticadaptation.cg.cpp.exceptions.IncorrectAmountOfElementsException
  12. import be.uantwerpen.ansymo.semanticadaptation.generator.SemanticAdaptationGenerator
  13. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
  14. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ControlRuleBlock
  15. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Declaration
  16. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InOutRules
  17. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMU
  18. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.MooreOrMealy
  19. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ParamDeclarations
  20. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port
  21. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.ReactiveOrDelayed
  22. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
  23. import java.io.File
  24. import java.util.ArrayList
  25. import java.util.Collection
  26. import java.util.LinkedHashMap
  27. import java.util.List
  28. import org.eclipse.emf.common.util.EList
  29. import org.eclipse.emf.ecore.resource.Resource
  30. import org.eclipse.xtext.generator.IFileSystemAccess2
  31. import org.eclipse.xtext.generator.IGeneratorContext
  32. class CppGenerator extends SemanticAdaptationGenerator {
  33. private var IFileSystemAccess2 fsa;
  34. private List<File> resourcePaths = newArrayList();
  35. override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
  36. this.fsa = fsa;
  37. for (SemanticAdaptation type : resource.allContents.toIterable.filter(SemanticAdaptation)) {
  38. type.compile;
  39. }
  40. }
  41. // TODO: Verify adaptation.name is not a C++ keyword
  42. def void compile(SemanticAdaptation adaptation) {
  43. for (Adaptation adap : adaptation.elements.filter(Adaptation)) {
  44. // Value used for scoping variables in the .sa file
  45. val adapInteralRefName = adap.name;
  46. // The CPP class name
  47. val adapClassName = adap.name.toFirstUpper;
  48. // This is the external name used in the model description file for the semantic adaptation FMU
  49. val adapExternalName = adap.type.name;
  50. // List of inner FMUs
  51. var ArrayList<InnerFMUData> innerFMUsData = newArrayList();
  52. val innerFmus = adap.inner.eAllContents.toList.filter(InnerFMU);
  53. if (innerFmus.isEmpty) {
  54. throw new IncorrectAmountOfElementsException("The adaptation does not contain any InnerFMUs.")
  55. }
  56. /*
  57. * This map will contain scalar variables from the FMUs defined in InnerFMU.
  58. * The structure is fmuName -> (SVName -> mappedSV) where SVName = mappedSV.name for easy lookup.
  59. * The mappedSV contains the original scalar variable and extra data such as define name.
  60. */
  61. var LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mappedScalarVariables = newLinkedHashMap();
  62. /*
  63. * Loading the FMU defined in InnerFMU, the related model description file and its scalar variables.
  64. */
  65. // TODO: Add support for multiple inner fmus. Only partially supported
  66. var ModelDescription md;
  67. for (fmu : adap.inner.eAllContents.toList.filter(InnerFMU)) {
  68. val fmuFile = new File(fmu.path.replace('\"', ''));
  69. this.resourcePaths.add(fmuFile);
  70. md = new ModelDescription(fmu.name, fmu.type.name, fmuFile);
  71. innerFMUsData.add(new InnerFMUData(fmu.name, fmu.type.name, md.guid));
  72. // fmus.add(fmu.name -> fmu.type.name);
  73. val LinkedHashMap<String, MappedScalarVariable> mSV = newLinkedHashMap();
  74. for (sv : md.sv.values) {
  75. var mappedSv = new MappedScalarVariable(sv);
  76. mappedSv.define = (mappedSv.mappedSv.owner + mappedSv.mappedSv.name).toUpperCase;
  77. mSV.put(mappedSv.mappedSv.name, mappedSv);
  78. }
  79. mappedScalarVariables.put(fmu.name, mSV);
  80. }
  81. // C++ Defines for accessing FMU scalar variables.
  82. val String fmusDefines = calcDefines(mappedScalarVariables);
  83. /*
  84. * This map contains all the ScalarVariables for the semantic adaptation.
  85. * Some of them are not populated yet, but they will be during the compilation of the in and out rule blocks.
  86. */
  87. var LinkedHashMap<String, SAScalarVariable> SASVs = calcSASVsFromInportsOutports(adapInteralRefName,
  88. adap.inports, adap.outports, mappedScalarVariables)
  89. // C++ defines for accessing semantic adaptation scalar variables
  90. val String SADefines = calcSADefines(SASVs.values);
  91. // Compile Params
  92. var LinkedHashMap<String, GlobalInOutVariable> params = newLinkedHashMap;
  93. val String paramsConstructorSource = compileParams(params, adap.params);
  94. // Handles cases like this: output ports tau <- loop_sa.tau
  95. var List<Port> outPortsWithSrcDep = newArrayList();
  96. if (adap.outports !== null) {
  97. outPortsWithSrcDep = adap.outports.filter[x|x.sourcedependency !== null].toList;
  98. }
  99. var List<Port> inPortsWithSrcDep = newArrayList();
  100. if (adap.inports !== null) {
  101. inPortsWithSrcDep = adap.inports.filter[x|x.targetdependency !== null].toList;
  102. }
  103. // The three rule blocks
  104. val inRuleBlock = adap.in;
  105. val outRuleBlock = adap.out;
  106. val crtlRuleBlock = adap.control;
  107. // Get the control vars, in vars, and out vars
  108. var inVars = if(inRuleBlock !== null) compileRuleBlockVars(inRuleBlock.globalInVars, params);
  109. var outVars = if(outRuleBlock !== null) compileRuleBlockVars(outRuleBlock.globalOutVars, params);
  110. val crtlVars = if(crtlRuleBlock !== null) compileRuleBlockVars(crtlRuleBlock.globalCtrlVars, params);
  111. /*
  112. * Support for source dependency: output ports tau <- loop_sa.tau
  113. * Only carried out for outVars.
  114. * TODO: Do for inVars
  115. */
  116. for (Port port : outPortsWithSrcDep) {
  117. val name = '''stored_«port.sourcedependency.owner.name»_«port.sourcedependency.port.name»''';
  118. val type = mappedScalarVariables.get(port.sourcedependency.owner.name).get(
  119. port.sourcedependency.port.name).mappedSv.type;
  120. val globVar = new GlobalInOutVariable(name, type);
  121. val sourceDepType = mappedScalarVariables.get(port.sourcedependency.owner.name).get(
  122. port.sourcedependency.port.name).mappedSv.type;
  123. val constructorInit = '''this->internalState.«name» = «Conversions.fmiTypeToCppDefaultValue(sourceDepType)»;'''
  124. if (outVars !== null) {
  125. outVars.value.put(name, globVar);
  126. outVars = outVars.key.concat(constructorInit) -> outVars.value;
  127. } else {
  128. val LinkedHashMap<String, GlobalInOutVariable> gVars = newLinkedHashMap();
  129. gVars.put(name, globVar)
  130. outVars = constructorInit -> gVars;
  131. }
  132. }
  133. for (Port port : inPortsWithSrcDep) {
  134. val dependency = port.targetdependency;
  135. val name = '''stored_«dependency.owner.name»_«dependency.port.name»'''
  136. val type = mappedScalarVariables.get(dependency.owner.name).get(dependency.port.name).mappedSv.type;
  137. val globVar = new GlobalInOutVariable(name, type);
  138. val constructorInit = '''this->internalState.«name» = «Conversions.fmiTypeToCppDefaultValue(type)»;''';
  139. if (inVars !== null) {
  140. inVars.value.put(name, globVar);
  141. inVars = inVars.key.concat("\n" + constructorInit) -> inVars.value;
  142. } else {
  143. val LinkedHashMap<String, GlobalInOutVariable> gVars = newLinkedHashMap();
  144. gVars.put(name, globVar);
  145. inVars = constructorInit -> gVars;
  146. }
  147. }
  148. // Compile the in rules
  149. val inRules = if(adap.in !== null) adap.in as InOutRules else null;
  150. val inRuleResult = compileInOutRuleBlocks(IORuleType.Input, inRules, adapClassName, adapInteralRefName,
  151. mappedScalarVariables, SASVs, params, if(inVars !== null) inVars.value else null,
  152. if(outVars !== null) outVars.value else null, if(crtlVars !== null) crtlVars.value else null,
  153. inPortsWithSrcDep);
  154. // Compile the out rules
  155. val outRules = if(adap.out !== null) adap.out as InOutRules else null;
  156. val outRuleResult = compileInOutRuleBlocks(IORuleType.Output, outRules, adapClassName,
  157. adapInteralRefName, mappedScalarVariables, SASVs, params,
  158. if(inVars !== null) inVars.value else null, if(outVars !== null) outVars.value else null,
  159. if(crtlVars !== null) crtlVars.value else null, outPortsWithSrcDep);
  160. // Compile the Control Rules. These might use the out vars, so pass these along.
  161. val crtlRules = if(adap.control !== null) adap.control else null;
  162. val crtlRuleResult = compileControlRuleBlock(crtlRules, adapClassName, adapInteralRefName,
  163. mappedScalarVariables, SASVs, params, if(inVars !== null) inVars.value else null,
  164. if(outVars !== null) outVars.value else null, if(crtlVars !== null) crtlVars.value else null);
  165. /*
  166. * Compile the constructor, destructor and initialize functions
  167. */
  168. val String deAndConstructorAndInitializeSource = compileDeAndConstructorAndInitialize(
  169. adapClassName,
  170. innerFMUsData,
  171. md.guid,
  172. paramsConstructorSource,
  173. if(inVars !== null) inVars.key else "",
  174. if(outVars !== null) outVars.key else "",
  175. if(crtlVars !== null) crtlVars.key else "",
  176. adap.machine,
  177. adap.reactiveness,
  178. inRules !== null || inPortsWithSrcDep.length > 0,
  179. outRules !== null || outPortsWithSrcDep.length > 0
  180. );
  181. /*
  182. * Compile getRuleThis function
  183. */
  184. val String getRuleThisSource = compileGetRuleThis(adapClassName);
  185. /*
  186. * The in and out rules have populated the semantic adaptation scalar variables we can generate the getFmiValue* and setFmiValue functions.
  187. */
  188. val String getFuncsSource = compileGetFmiValueFunctions(adapClassName, SASVs);
  189. val String setFuncsSource = compileSetFmiValueFunctions(adapClassName, SASVs);
  190. // Compile the state functions
  191. val Pair<String,String> stateFunctions = compileStateFunctions(adapClassName);
  192. // Compile the source file
  193. val String sourceInclude = '''#include "«adapClassName».h"''';
  194. val sourceFile = compileSource(
  195. sourceInclude,
  196. deAndConstructorAndInitializeSource,
  197. getRuleThisSource,
  198. getFuncsSource,
  199. setFuncsSource,
  200. inRuleResult.generatedCpp,
  201. outRuleResult.generatedCpp,
  202. crtlRuleResult.generatedCpp,
  203. stateFunctions.value
  204. );
  205. fsa.generateFile(adapClassName + ".cpp", sourceFile);
  206. // Merge the global variables for use in compiling the header file.
  207. // TODO: Check for duplicates
  208. var LinkedHashMap<String, GlobalInOutVariable> allGVars = newLinkedHashMap();
  209. allGVars.putAll(params);
  210. if (inVars !== null)
  211. allGVars.putAll(inVars.value);
  212. if (outVars !== null)
  213. allGVars.putAll(outVars.value);
  214. if (crtlVars !== null)
  215. allGVars.putAll(crtlVars.value);
  216. // Compile the header file
  217. val headerFile = compileHeader(
  218. adapClassName,
  219. fmusDefines,
  220. SADefines,
  221. inRuleResult.functionSignatures,
  222. outRuleResult.functionSignatures,
  223. crtlRuleResult.functionSignatures,
  224. allGVars,
  225. innerFMUsData,
  226. SASVs.values.map[CalcSVar()].toList,
  227. stateFunctions.key
  228. );
  229. fsa.generateFile(adapClassName + ".h", headerFile);
  230. // Compile the model description file
  231. val modelDescCreator = new ModelDescriptionCreator(adapExternalName);
  232. val modelDescription = modelDescCreator.generateModelDescription(SASVs.values);
  233. fsa.generateFile("modelDescription.xml", modelDescription);
  234. // Compile the fmu.cpp file
  235. val fmuCppFile = FmuGenerator.genFmuCppFile(adapClassName);
  236. fsa.generateFile("Fmu.cpp", fmuCppFile);
  237. fsa.generateFile("CMakeLists.txt",CMakeListsGenerator.generateCMakeLists(adapExternalName))
  238. fsa.generateFile("msys-toolchain.cmake",CMakeListsGenerator.generateToolChainCmake());
  239. }
  240. }
  241. def String compileParams(LinkedHashMap<String, GlobalInOutVariable> gVars, EList<ParamDeclarations> params) {
  242. val paramsConditionSwitch = new ParamConditionSwitch(gVars);
  243. var String paramsConstructorSource = "";
  244. for (paramDecl : params) {
  245. val doSwitchRes = paramsConditionSwitch.doSwitch(paramDecl);
  246. paramsConstructorSource += doSwitchRes.code;
  247. }
  248. return paramsConstructorSource;
  249. }
  250. def calcSADefines(Collection<SAScalarVariable> variables) {
  251. var ArrayList<String> defines = newArrayList();
  252. for (SASV : variables) {
  253. defines.add("#define " + SASV.defineName + " " + SASV.valueReference);
  254. }
  255. return defines.join("\n");
  256. }
  257. def calcDefines(LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> map) {
  258. var ArrayList<String> defines = newArrayList();
  259. for (fmuEntries : map.entrySet) {
  260. for (MappedScalarVariable mSV : fmuEntries.value.values) {
  261. defines.add("#define " + mSV.define.replace('(','_').replace(')','_') + " " + mSV.valueReference);
  262. }
  263. }
  264. return defines.join("\n");
  265. }
  266. def Pair<String,String> compileStateFunctions(String saName)
  267. {
  268. return
  269. '''
  270. fmi2FMUstate getInternalFMUState();
  271. void setInternalFMUState(fmi2FMUstate state);
  272. void freeInternalFMUState(fmi2FMUstate state);
  273. '''
  274. ->
  275. '''
  276. fmi2FMUstate «saName»::getInternalFMUState()
  277. {
  278. InternalState* s = new InternalState();
  279. *s = this->internalState;
  280. return s;
  281. }
  282. void «saName»::setInternalFMUState(fmi2FMUstate state)
  283. {
  284. this->internalState = *(InternalState*)state;
  285. }
  286. void «saName»::freeInternalFMUState(fmi2FMUstate state)
  287. {
  288. delete (InternalState*)state;
  289. }''';
  290. }
  291. // Compiles the final source file
  292. def String compileSource(String include, String constructor, String getRuleThis, String getFunctions,
  293. String setFunctions, String inFunctions, String outFunctions, String controlFunction, String stateFunctions) {
  294. return '''
  295. «include»
  296. namespace adaptation
  297. {
  298. «constructor»
  299. «getRuleThis»
  300. «getFunctions»
  301. «setFunctions»
  302. «inFunctions»
  303. «controlFunction»
  304. «outFunctions»
  305. «stateFunctions»
  306. }
  307. '''
  308. }
  309. /*
  310. * Compiles the header file split into two: The first part contains the includes and using namespace definitions and start the ,
  311. * the second part contains the class
  312. */
  313. def String compileHeader(String adapClassName, String fmusDefines, String SADefines,
  314. List<String> inRulesFuncSig, List<String> outRulesFuncSig, List<String> crtlRulesFuncSig,
  315. LinkedHashMap<String, GlobalInOutVariable> globalVariables, ArrayList<InnerFMUData> fmus,
  316. Collection<ScalarVariable> sVars, String stateFunctions) {
  317. return '''
  318. #ifndef SRC_«adapClassName.toUpperCase»_H
  319. #define SRC_«adapClassName.toUpperCase»_H
  320. #include "SemanticAdaptation.h"
  321. #include "HyfMath.h"
  322. #include <memory>
  323. #include "Fmu.h"
  324. using namespace std;
  325. using namespace fmi2;
  326. namespace adaptation
  327. {
  328. «fmusDefines»
  329. «SADefines»
  330. class «adapClassName» : public SemanticAdaptation<«adapClassName»>, public enable_shared_from_this<«adapClassName»>
  331. {
  332. public:
  333. «adapClassName»(shared_ptr<std::string> fmiInstanceName, shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions);
  334. void initialize();
  335. virtual ~«adapClassName»();
  336. void setFmiValue(fmi2ValueReference id, int value);
  337. void setFmiValue(fmi2ValueReference id, bool value);
  338. void setFmiValue(fmi2ValueReference id, double value);
  339. void setFmiValue(fmi2ValueReference id, string value);
  340. int getFmiValueInteger(fmi2ValueReference id);
  341. bool getFmiValueBoolean(fmi2ValueReference id);
  342. double getFmiValueReal(fmi2ValueReference id);
  343. string getFmiValueString(fmi2ValueReference id);
  344. protected:
  345. «stateFunctions»
  346. private:
  347. «adapClassName»* getRuleThis();
  348. /*in rules*/
  349. «inRulesFuncSig.map[x | x+";"].join("\n")»
  350. /*out rules*/
  351. «outRulesFuncSig.map[x | x+";"].join("\n")»
  352. «crtlRulesFuncSig.map[x | x+";"].join("\n")»
  353. «FOR fmu : fmus»
  354. shared_ptr<FmuComponent> «fmu.name»;
  355. «ENDFOR»
  356. struct InternalState {
  357. «FOR sv : sVars»
  358. «Conversions.fmiTypeToCppType(sv.type)» «sv.name»;
  359. «IF sv.causality == SVCausality.input»
  360. bool isSet«sv.name»;
  361. «ENDIF»
  362. «ENDFOR»
  363. «FOR v : globalVariables.entrySet»
  364. «Conversions.fmiTypeToCppType(v.value.type)» «v.key»;
  365. «ENDFOR»
  366. };
  367. InternalState internalState;
  368. };
  369. }
  370. #endif
  371. ''';
  372. }
  373. /*
  374. * Compiles the source file constructor, destructor and the initialize function
  375. */
  376. def String compileDeAndConstructorAndInitialize(String adapClassName, ArrayList<InnerFMUData> fmus, String guid,
  377. String paramsCons, String inCons, String outCons, String crtlCons, MooreOrMealy machineType,
  378. ReactiveOrDelayed reactiveOrDealyed, boolean inputRules, boolean outputRules) {
  379. var ArrayList<String> initialisations = newArrayList();
  380. if (reactiveOrDealyed == ReactiveOrDelayed.DELAYED) {
  381. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Delayed;''');
  382. } else if (reactiveOrDealyed == ReactiveOrDelayed.REACTIVE) {
  383. initialisations.add('''this->reactiveness = ReactiveOrDelayed::Reactive;''');
  384. }
  385. if (machineType == MooreOrMealy.MOORE) {
  386. initialisations.add('''this->machineType = MooreOrMealy::Moore;''');
  387. } else if (machineType == MooreOrMealy.MEALY) {
  388. initialisations.add('''this->machineType = MooreOrMealy::Mealy;''');
  389. }
  390. var pathCount = 1;
  391. for (fmu : fmus) {
  392. val pathName = '''path«pathCount»''';
  393. pathCount++;
  394. initialisations.add('''
  395. auto «pathName» = make_shared<string>(*resourceLocation);
  396. «pathName»->append(string("«fmu.typeName».fmu"));
  397. auto «fmu.name»Fmu = make_shared<fmi2::Fmu>(*«pathName»);
  398. «fmu.name»Fmu->initialize();
  399. this->«fmu.name» = «fmu.name»Fmu->instantiate("«fmu.name»",fmi2CoSimulation, "«fmu.guid»", true, true, shared_from_this());
  400. if(this->«fmu.name»->component == NULL)
  401. this->lastErrorState = fmi2Fatal;
  402. this->instances->push_back(this->«fmu.name»);
  403. ''');
  404. }
  405. return '''
  406. «adapClassName»::«adapClassName»(shared_ptr<std::string> fmiInstanceName,shared_ptr<string> resourceLocation, const fmi2CallbackFunctions* functions) :
  407. SemanticAdaptation(fmiInstanceName, resourceLocation, «if(inputRules) "createInputRules()" else "NULL"», «if(outputRules) "createOutputRules()" else "NULL"», functions)
  408. {
  409. «paramsCons»
  410. «inCons»
  411. «outCons»
  412. «crtlCons»
  413. }
  414. void «adapClassName»::initialize()
  415. {
  416. «initialisations.join("\r\n")»
  417. }
  418. «adapClassName»::~«adapClassName»()
  419. {
  420. }
  421. ''';
  422. }
  423. /*
  424. * Compiles the source file function getRuleThis
  425. */
  426. def String compileGetRuleThis(String adaptationName) {
  427. return '''
  428. «adaptationName»* «adaptationName»::getRuleThis()
  429. {
  430. return this;
  431. }
  432. '''
  433. }
  434. /*
  435. * Compiles the source file functions getFmiValue<double, int, string, bool>
  436. */
  437. def String compileGetFmiValueFunctions(String adaptationName,
  438. LinkedHashMap<String, SAScalarVariable> variables) {
  439. var ArrayList<String> cpp = newArrayList();
  440. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].toList;
  441. var convertedSASVsOrdered = convertedSASVs.filter[causality === SVCausality.output].groupBy[type];
  442. for (SVType type : SVType.values) {
  443. val functionSignature = '''«Conversions.fmiTypeToCppType(type)» «adaptationName»::getFmiValue«type.toString»(fmi2ValueReference id)''';
  444. val functionReturn = '''return «Conversions.fmiTypeToCppDefaultValue(type)»''';
  445. if (convertedSASVsOrdered.containsKey(type)) {
  446. cpp.add(
  447. '''
  448. «functionSignature»
  449. {
  450. «Utilities.getDebug(functionSignature)»
  451. switch (id)
  452. {
  453. «FOR svInner : convertedSASVsOrdered.get(type)»
  454. case «variables.get(svInner.name).defineName»:
  455. {
  456. return this->internalState.«svInner.name»;
  457. }
  458. «ENDFOR»
  459. default:
  460. {
  461. «functionReturn»;
  462. }
  463. }
  464. }
  465. '''
  466. );
  467. } else {
  468. cpp.add(
  469. '''
  470. «functionSignature»
  471. {
  472. «Utilities.getDebug(functionSignature)»
  473. «functionReturn»;
  474. }
  475. '''
  476. );
  477. }
  478. }
  479. return cpp.join("\n");
  480. }
  481. /*
  482. * Compiles the source file functions setFmiValue<double, int, string, bool>*
  483. */
  484. def String compileSetFmiValueFunctions(String adapClassName,
  485. LinkedHashMap<String, SAScalarVariable> variables) {
  486. var ArrayList<String> cpp = newArrayList();
  487. var List<ScalarVariable> convertedSASVs = variables.values.map[CalcSVar()].filter [
  488. causality === SVCausality.input
  489. ].toList;
  490. var convertedSASVsOrdered = convertedSASVs.groupBy[type];
  491. for (SVType type : SVType.values) {
  492. val functionSignature = '''void «adapClassName»::setFmiValue(fmi2ValueReference id, «Conversions.fmiTypeToCppType(type)» value)''';
  493. cpp.add(
  494. '''
  495. «functionSignature»
  496. {
  497. «Utilities.getDebug(functionSignature)»
  498. «IF convertedSASVsOrdered.containsKey(type)»
  499. switch (id)
  500. {
  501. «FOR svInner : convertedSASVsOrdered.get(type)»
  502. case «variables.get(svInner.name).defineName»:
  503. {
  504. this->internalState.«svInner.name» = value;
  505. this->internalState.isSet«svInner.name» = true;
  506. break;
  507. }
  508. «ENDFOR»
  509. default:
  510. {
  511. }
  512. }
  513. «ENDIF»
  514. }
  515. '''
  516. );
  517. }
  518. return cpp.join("\n");
  519. }
  520. /*
  521. * Compiles the source file function executeInternalControlFlow.
  522. * Calculates necessary information on function signatures necessary for generation of the header file.
  523. */
  524. def InOutRulesBlockResult compileControlRuleBlock(ControlRuleBlock crtlRuleBlock, String adaptationClassName,
  525. String adaptationName, LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  526. LinkedHashMap<String, SAScalarVariable> SASVs, LinkedHashMap<String, GlobalInOutVariable> params,
  527. LinkedHashMap<String, GlobalInOutVariable> inVars, LinkedHashMap<String, GlobalInOutVariable> outVars,
  528. LinkedHashMap<String, GlobalInOutVariable> crtlVars) {
  529. var cpp = "";
  530. val visitor = new ControlConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  531. outVars, crtlVars);
  532. if (crtlRuleBlock !== null)
  533. cpp += visitor.doSwitch(crtlRuleBlock).code;
  534. return new InOutRulesBlockResult(cpp, visitor.functionSignatures);
  535. }
  536. def String SplitAtSpaceAndRemoveFirst(String content) {
  537. content.substring(content.indexOf(" ") + 1, content.length);
  538. }
  539. def String removeEmptyArgumentParenthesis(String content) {
  540. return content.substring(0, content.length - 2);
  541. }
  542. def String removeArgumentParenthesis(String content) {
  543. val startParen = content.indexOf('(');
  544. return content.substring(0,startParen);
  545. }
  546. /*
  547. * Calculates necessary information on global in/out variables
  548. */
  549. def Pair<String, LinkedHashMap<String, GlobalInOutVariable>> compileRuleBlockVars(EList<Declaration> gVars,
  550. LinkedHashMap<String, GlobalInOutVariable> params) {
  551. val visitor = new RulesConditionSwitch("", "", "", null, null, params, null, null, null)
  552. return visitor.getGlobalVars(gVars);
  553. }
  554. /*
  555. * Compiles the source file functions <in/out>_rule_<condition, body, flush>.
  556. * Calculates necessary information on function signatures necessary for generation of the header file.
  557. * Added the extra input and output functions
  558. */
  559. def InOutRulesBlockResult compileInOutRuleBlocks(
  560. IORuleType ioType,
  561. InOutRules rulesBlock,
  562. String adaptationClassName,
  563. String adaptationName,
  564. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVars,
  565. LinkedHashMap<String, SAScalarVariable> SASVs,
  566. LinkedHashMap<String, GlobalInOutVariable> params,
  567. LinkedHashMap<String, GlobalInOutVariable> inVars,
  568. LinkedHashMap<String, GlobalInOutVariable> outVars,
  569. LinkedHashMap<String, GlobalInOutVariable> crtlVars,
  570. List<Port> portsWithSrcDep
  571. ) {
  572. val visitor = if (ioType == IORuleType.Input)
  573. new InRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  574. outVars, crtlVars)
  575. else
  576. new OutRulesConditionSwitch(adaptationClassName, adaptationName, mSVars, SASVs, params, inVars,
  577. outVars, crtlVars);
  578. val functionName = "create" + ioType + "Rules()";
  579. var String cpp = "";
  580. var List<String> allFunctionSignatures = newArrayList();
  581. if (rulesBlock !== null) {
  582. cpp += visitor.doSwitch(rulesBlock).code;
  583. }
  584. if (!visitor.functionSignatures.empty || !portsWithSrcDep.empty) {
  585. allFunctionSignatures.addAll(visitor.functionSignatures);
  586. var ArrayList<String> createRulesFunction = newArrayList();
  587. if (rulesBlock !== null) {
  588. // For-loop Handles the out rules defined in the sa file
  589. for (var int i = 0; i < (visitor.functionSignatures.length); i += 3) {
  590. createRulesFunction.add(
  591. '''
  592. list->push_back(
  593. (Rule<«adaptationClassName»>){
  594. &«adaptationClassName»::«visitor.functionSignatures.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  595. &«adaptationClassName»::«visitor.functionSignatures.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  596. &«adaptationClassName»::«visitor.functionSignatures.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  597. });
  598. ''');
  599. }
  600. }
  601. var List<String> depFunctionSource = newArrayList();
  602. var List<String> depFunctionSignatures = newArrayList();
  603. for (var int i = 0; i < portsWithSrcDep.length; i++) {
  604. val currentPort = portsWithSrcDep.get(i);
  605. // Output ports uses source dependencies.
  606. // Input ports uses target dependencies;
  607. val dependency = (if (ioType == IORuleType.Input)
  608. currentPort.targetdependency
  609. else
  610. currentPort.sourcedependency);
  611. val newCount = visitor.functionSignatures.length + i + 1;
  612. val funcSigCon = visitor.createFunctionSignature('''condition''', "bool", newCount,
  613. depFunctionSignatures)
  614. val funcSigBody = visitor.createFunctionSignature('''body''', "void", newCount,
  615. depFunctionSignatures)
  616. val funcSigFlush = visitor.createFunctionSignature('''flush''', "void", newCount,
  617. depFunctionSignatures)
  618. val type = mSVars.get(dependency.owner.name).get(dependency.port.name).mappedSv.type;
  619. val define = mSVars.get(dependency.owner.name).get(dependency.port.name).define;
  620. var ruleCpp = "";
  621. if (ioType == IORuleType.Output) {
  622. val getValueCpp = '''getValue«Conversions.fmiTypeToGetValueString(type)»(«dependency.owner.name»,«define»)''';
  623. ruleCpp = '''
  624. «funcSigCon»{
  625. «Utilities.getDebug(funcSigCon)»
  626. return true;
  627. }
  628. «funcSigBody»{
  629. «Utilities.getDebug(funcSigBody)»
  630. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = «getValueCpp»;
  631. }
  632. «funcSigFlush»{
  633. «Utilities.getDebug(funcSigFlush)»
  634. this->internalState.«currentPort.name» = this->internalState.stored_«dependency.owner.name»_«dependency.port.name»;
  635. }
  636. '''
  637. } else if (ioType == IORuleType.Input) {
  638. val setValueCpp = '''setValue(«dependency.owner.name»,«define»,this->internalState.stored_«dependency.owner.name»_«dependency.port.name»);''';
  639. ruleCpp = '''
  640. «funcSigCon»{
  641. «Utilities.getDebug(funcSigCon)»
  642. return true;
  643. }
  644. «funcSigBody»{
  645. «Utilities.getDebug(funcSigBody)»
  646. this->internalState.stored_«dependency.owner.name»_«dependency.port.name» = this->internalState.«currentPort.name»;
  647. }
  648. «funcSigFlush»{
  649. «Utilities.getDebug(funcSigFlush)»
  650. «setValueCpp»
  651. }
  652. '''
  653. }
  654. cpp += ruleCpp;
  655. depFunctionSource.add(funcSigCon);
  656. depFunctionSource.add(funcSigBody);
  657. depFunctionSource.add(funcSigFlush);
  658. }
  659. allFunctionSignatures.addAll(depFunctionSignatures);
  660. for (var int i = 0; i < (depFunctionSource.length); i += 3) {
  661. createRulesFunction.add(
  662. '''
  663. list->push_back(
  664. (Rule<«adaptationClassName»>){
  665. &«depFunctionSource.get(i).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  666. &«depFunctionSource.get(i+1).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»,
  667. &«depFunctionSource.get(i+2).SplitAtSpaceAndRemoveFirst.removeArgumentParenthesis»
  668. });
  669. ''');
  670. }
  671. // Handles the createOutputRules and createInputRules
  672. val functionPrefix = '''shared_ptr<list<Rule<«adaptationClassName»>>>''';
  673. allFunctionSignatures.add(functionPrefix + " " + functionName)
  674. cpp += '''
  675. «functionPrefix» «adaptationClassName»::«functionName»
  676. {
  677. auto list = make_shared<std::list<Rule<«adaptationClassName»>>>();
  678. «createRulesFunction.join("\n")»
  679. return list;
  680. }
  681. '''
  682. }
  683. return new InOutRulesBlockResult(cpp, allFunctionSignatures);
  684. }
  685. /*
  686. * Calculates the semantic adaptation scalar variables via input ports and output ports.
  687. * Note: These a not fully populated yet as the in rules and out rules must be compiled first.
  688. */
  689. def LinkedHashMap<String, SAScalarVariable> calcSASVsFromInportsOutports(String definePrefix,
  690. EList<Port> inports, EList<Port> outports,
  691. LinkedHashMap<String, LinkedHashMap<String, MappedScalarVariable>> mSVs) {
  692. var LinkedHashMap<String, SAScalarVariable> saSVs = newLinkedHashMap();
  693. var int valueReference = 0;
  694. for (inport : inports) {
  695. var saSV = new SAScalarVariable();
  696. saSV.SetPartOfMD(true);
  697. saSV.valueReference = valueReference++;
  698. saSV.name = inport.name;
  699. saSV.defineName = (definePrefix + inport.name).toUpperCase
  700. saSV.causality = SVCausality.input;
  701. saSVs.put(saSV.name, saSV);
  702. if (inport.targetdependency !== null) {
  703. saSV.type = mSVs.get(inport.targetdependency.owner.name).get(inport.targetdependency.port.name).
  704. mappedSv.type;
  705. saSV.variability = mSVs.get(inport.targetdependency.owner.name).get(
  706. inport.targetdependency.port.name).mappedSv.variability;
  707. }
  708. }
  709. for (outport : outports) {
  710. var saSV = new SAScalarVariable();
  711. if (outport.sourcedependency !== null) {
  712. saSV.type = mSVs.get(outport.sourcedependency.owner.name).get(outport.sourcedependency.port.name).
  713. mappedSv.type;
  714. saSV.variability = mSVs.get(outport.sourcedependency.owner.name).get(
  715. outport.sourcedependency.port.name).mappedSv.variability;
  716. }
  717. saSV.SetPartOfMD(true);
  718. saSV.valueReference = valueReference++;
  719. saSV.defineName = (definePrefix + outport.name).toUpperCase
  720. saSV.name = outport.name;
  721. saSV.causality = SVCausality.output;
  722. saSVs.put(saSV.name, saSV);
  723. }
  724. return saSVs;
  725. }
  726. def List<File> getResourcePaths() {
  727. return resourcePaths;
  728. }
  729. }