SemanticAdaptationCanonicalGenerator.xtend 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. /*
  2. * generated by Xtext 2.10.0
  3. */
  4. package be.uantwerpen.ansymo.semanticadaptation.generator
  5. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Adaptation
  6. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BoolLiteral
  7. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.BuiltinFunction
  8. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Close
  9. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.CompositeOutputFunction
  10. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Connection
  11. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DataRule
  12. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.DeclaredParameter
  13. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Expression
  14. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.FMU
  15. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMU
  16. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclaration
  17. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.InnerFMUDeclarationFull
  18. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IntLiteral
  19. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.IsSet
  20. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.OutputFunction
  21. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Port
  22. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.RealLiteral
  23. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptation
  24. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SemanticAdaptationFactory
  25. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleParamDeclaration
  26. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.SingleVarDeclaration
  27. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.StateTransitionFunction
  28. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.StringLiteral
  29. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Unity
  30. import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable
  31. import java.io.ByteArrayOutputStream
  32. import java.util.HashMap
  33. import java.util.LinkedList
  34. import java.util.Map
  35. import org.eclipse.emf.ecore.EObject
  36. import org.eclipse.emf.ecore.resource.Resource
  37. import org.eclipse.xtext.EcoreUtil2
  38. import org.eclipse.xtext.generator.AbstractGenerator
  39. import org.eclipse.xtext.generator.IFileSystemAccess2
  40. import org.eclipse.xtext.generator.IGeneratorContext
  41. import java.util.List
  42. /**
  43. * Generates code from your model files on save.
  44. *
  45. * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
  46. */
  47. class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
  48. String CANONICAL_EXT = ".BASE.sa"
  49. String NAME_SUFFIX = "_BASE"
  50. override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
  51. Log.push("Generating canonical semantic adaptation for file " + resource.URI.toFileString() + "...")
  52. Log.println("Resource URI information:")
  53. Log.println("\t resource.URI.lastSegment = " + resource.URI.lastSegment())
  54. Log.println("\t resource.URI.trimFileExtension = " + resource.URI.trimFileExtension())
  55. // Create in memory representation of canonical SA file
  56. var adaptations = resource.allContents.toIterable.filter(SemanticAdaptation).last.elements.filter(Adaptation);
  57. if (adaptations.size > 1){
  58. throw new Exception("Only one semantic adaptation is supported per .sa file")
  59. }
  60. var adaptation = adaptations.head
  61. Log.println(prettyprint_model(adaptation, "File Read"))
  62. // Create file name for the canonical sa file
  63. var fileNameWithoutExt = resource.URI.trimFileExtension().lastSegment()
  64. var canonicalFileName = fileNameWithoutExt + CANONICAL_EXT
  65. Log.println("canonicalFileName = " + canonicalFileName)
  66. Log.println("Checking if file is already a canonical version...")
  67. if (adaptation.name.indexOf(NAME_SUFFIX) == -1){
  68. Log.println("It is not.")
  69. adaptation.name = adaptation.name + NAME_SUFFIX
  70. canonicalize(adaptation)
  71. Log.println(prettyprint_model(adaptation, "Generated File"))
  72. fsa.generateFile(canonicalFileName, adaptation.serialize_model)
  73. Log.println("File " + canonicalFileName + " written.")
  74. } else {
  75. Log.println("It is already a canonical version.")
  76. Log.println("Nothing to do.")
  77. }
  78. Log.pop("Generating canonical semantic adaptation for file " + resource.URI.toFileString() + "... DONE.")
  79. }
  80. def prettyprint_model(Adaptation sa, String title){
  81. var outputByteArray = new ByteArrayOutputStream()
  82. sa.eResource.save(outputByteArray,null)
  83. return "______________________________" + title + "______________________________\n" +
  84. sa.serialize_model +
  85. "\n__________________________________________________________________________"
  86. }
  87. def serialize_model(Adaptation sa){
  88. var outputByteArray = new ByteArrayOutputStream()
  89. sa.eResource.save(outputByteArray,null)
  90. return outputByteArray.toString()
  91. }
  92. def inferUnits(Adaptation sa){
  93. // Unit inference
  94. var unitlessElements = genericDeclarationInferenceAlgorithm(sa ,
  95. [// getField
  96. element | {
  97. var DUMMY_UNIT = "Dips"
  98. if (element instanceof SingleParamDeclaration) {
  99. return DUMMY_UNIT
  100. } else if (element instanceof Port){
  101. return element.unity
  102. } else if (element instanceof SingleVarDeclaration){
  103. return DUMMY_UNIT
  104. } else {
  105. throw new Exception("Unexpected element type: " + element)
  106. }
  107. }
  108. ],
  109. [// setField
  110. element, value | {
  111. if (element instanceof SingleParamDeclaration) {
  112. } else if (element instanceof Port){
  113. element.unity = EcoreUtil2.copy(value as Unity)
  114. } else if (element instanceof SingleVarDeclaration){
  115. } else {
  116. throw new Exception("Unexpected element type: " + element)
  117. }
  118. }
  119. ],
  120. [// inferField
  121. element | {
  122. var DUMMY_UNIT = "Dips"
  123. if (element instanceof SingleParamDeclaration) {
  124. return DUMMY_UNIT
  125. } else if (element instanceof Port){
  126. return getPortUnit(element)
  127. } else if (element instanceof SingleVarDeclaration){
  128. return DUMMY_UNIT
  129. } else {
  130. throw new Exception("Unexpected element type: " + element)
  131. }
  132. }
  133. ]
  134. )
  135. if (unitlessElements > 0){
  136. Log.println("Could not infer all element units. There are " + unitlessElements + " unitless elements.")
  137. }
  138. }
  139. def inferTypes(Adaptation sa){
  140. // Type inference
  141. var untypedElements = genericDeclarationInferenceAlgorithm(sa ,
  142. [// getField
  143. element | {
  144. if (element instanceof SingleParamDeclaration) {
  145. return element.type
  146. } else if (element instanceof Port){
  147. return element.type
  148. } else if (element instanceof SingleVarDeclaration){
  149. return element.type
  150. } else {
  151. throw new Exception("Unexpected element type: " + element)
  152. }
  153. }
  154. ],
  155. [// setField
  156. element, value | {
  157. if (element instanceof SingleParamDeclaration) {
  158. element.type = value as String
  159. } else if (element instanceof Port){
  160. element.type = value as String
  161. } else if (element instanceof SingleVarDeclaration){
  162. element.type = value as String
  163. } else {
  164. throw new Exception("Unexpected element type: " + element)
  165. }
  166. }
  167. ],
  168. [// inferField
  169. element | {
  170. if (element instanceof SingleParamDeclaration) {
  171. return extractTypeFromExpression(element.expr, element.name)
  172. } else if (element instanceof Port){
  173. return getPortType(element)
  174. } else if (element instanceof SingleVarDeclaration){
  175. return extractTypeFromExpression(element.expr, element.name)
  176. } else {
  177. throw new Exception("Unexpected element type: " + element)
  178. }
  179. }
  180. ]
  181. )
  182. if (untypedElements > 0){
  183. Log.println("Error: Could not infer all types. There are " + untypedElements + " untyped elements.")
  184. Log.println(prettyprint_model(sa, "Current File"))
  185. throw new Exception("Could not infer all types. There are " + untypedElements + " untyped elements.")
  186. }
  187. }
  188. def canonicalize(Adaptation sa){
  189. Log.push("Canonicalize")
  190. inferUnits(sa)
  191. inferTypes(sa)
  192. addInPorts(sa)
  193. val inputPort2parameterDeclaration = addInParams(sa)
  194. val inputPort2InVarDeclaration = addInVars(sa, inputPort2parameterDeclaration)
  195. addInRules_External2Stored_Assignments(sa, inputPort2InVarDeclaration)
  196. val internalPort2ExternalPortBindings = findAllExternalPort2InputPort_Bindings(sa)
  197. addInRules_External2Internal_Assignments(sa, internalPort2ExternalPortBindings)
  198. removeInBindings(internalPort2ExternalPortBindings, sa)
  199. //addOutPorts(sa)
  200. Log.pop("Canonicalize")
  201. }
  202. def removeInBindings(HashMap<Port, Port> internalPort2ExternalPortBindings, Adaptation sa) {
  203. Log.push("removeInBindings")
  204. for (internalPort : internalPort2ExternalPortBindings.keySet){
  205. val externalPort = internalPort2ExternalPortBindings.get(internalPort)
  206. Log.println("Removing binding " + externalPort.name + "->" + internalPort.name)
  207. externalPort.targetdependency = null
  208. }
  209. Log.pop("removeInBindings")
  210. }
  211. def findAllExternalPort2InputPort_Bindings(Adaptation sa) {
  212. Log.push("findAllExternalPort2InputPort_Bindings")
  213. val internalPort2ExternalPortBindings = new HashMap<Port, Port>()
  214. for (port : getAllInnerFMUInputPortDeclarations(sa)){
  215. var parentFMU = port.eContainer as InnerFMU
  216. Log.println("Checking if port " + parentFMU.name + "." + port.name + " is bound to an external port.")
  217. val externalPort = findExternalPortByTargetDependency(sa, port)
  218. if (externalPort !== null){
  219. Log.println("Port " + parentFMU.name + "." + port.name + " is bound to an external port: " + externalPort.name)
  220. internalPort2ExternalPortBindings.put(port, externalPort)
  221. } else {
  222. Log.println("Port " + parentFMU.name + "." + port.name + " is not bound to an external port.")
  223. }
  224. }
  225. Log.pop("findAllExternalPort2InputPort_Bindings")
  226. return internalPort2ExternalPortBindings
  227. }
  228. def createExternalPortNameFromInternalPort(String parentFMUName, String internalPortName) {
  229. //return parentFMUName + "__" + internalPortName // Violates transparency
  230. return internalPortName
  231. }
  232. def addInRules_External2Internal_Assignments(Adaptation sa, HashMap<Port, Port> internalPort2ExternalPort) {
  233. Log.push("addInRules_External2Internal_Assignments")
  234. val dataRule = getOrPrependTrueInRule(sa)
  235. for(internalPort : internalPort2ExternalPort.keySet){
  236. val externalPort = internalPort2ExternalPort.get(internalPort)
  237. addAssignmentToInternalPort(dataRule.outputfunction, internalPort, externalPort)
  238. }
  239. Log.pop("addInRules_External2Internal_Assignments")
  240. }
  241. def addAssignmentToInternalPort(OutputFunction function, Port internalPort, Port externalPort) {
  242. Log.push("addAssignmentToInternalPort")
  243. if(! (function instanceof CompositeOutputFunction) ){
  244. throw new Exception("Only CompositeOutputFunction is supported for now.")
  245. }
  246. val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment()
  247. assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  248. (assignment.lvalue as Variable).owner = internalPort.eContainer as InnerFMU
  249. (assignment.lvalue as Variable).ref = internalPort
  250. assignment.expr = SemanticAdaptationFactory.eINSTANCE.createVariable()
  251. (assignment.expr as Variable).owner = externalPort.eContainer as Adaptation
  252. (assignment.expr as Variable).ref = externalPort
  253. val outFunction = function as CompositeOutputFunction
  254. outFunction.statements.add(0, assignment)
  255. Log.println("Assignment " + internalPort.name + " := " + externalPort.name + " created.")
  256. Log.pop("addAssignmentToInternalPort")
  257. }
  258. def addInRules_External2Stored_Assignments(Adaptation sa, HashMap<Port, SingleVarDeclaration> inputPort2InVarDeclaration) {
  259. Log.push("addInRules_External2Stored_Assignments")
  260. val dataRule = getOrPrependTrueInRule(sa)
  261. for(inPort : inputPort2InVarDeclaration.keySet){
  262. val storedVarDecl = inputPort2InVarDeclaration.get(inPort)
  263. addAssignmentToStoredVar(dataRule.statetransitionfunction, inPort, storedVarDecl)
  264. }
  265. Log.pop("addInRules_External2Stored_Assignments")
  266. }
  267. def addAssignmentToStoredVar(StateTransitionFunction function, Port inPort, SingleVarDeclaration storedVarDecl) {
  268. Log.push("addAssignmentToStoredVar")
  269. if (function.expression !== null){
  270. throw new Exception("Expressions in rules are not supported yet.")
  271. // This and the one below are asily solved with a syntactic sugar substitution.
  272. }
  273. if (function.assignment !== null){
  274. throw new Exception("Assignment in rules are not supported yet.")
  275. }
  276. val assignment = SemanticAdaptationFactory.eINSTANCE.createAssignment()
  277. assignment.lvalue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  278. assignment.lvalue.ref = storedVarDecl
  279. assignment.expr = SemanticAdaptationFactory.eINSTANCE.createVariable()
  280. (assignment.expr as Variable).owner = inPort.eContainer as Adaptation
  281. (assignment.expr as Variable).ref = inPort
  282. function.statements.add(0, assignment)
  283. Log.println("Assignment " + storedVarDecl.name + " := " + inPort.name + " created.")
  284. Log.pop("addAssignmentToStoredVar")
  285. }
  286. def getOrPrependTrueInRule(Adaptation sa) {
  287. if (sa.in === null){
  288. sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock()
  289. }
  290. var DataRule rule = null
  291. if (sa.in.rules.size == 0 || !isTrueRule(sa.in.rules.head)){
  292. Log.println("No existing rule found with true condition. Creating one.")
  293. val trueRule = SemanticAdaptationFactory.eINSTANCE.createDataRule()
  294. trueRule.condition = SemanticAdaptationFactory.eINSTANCE.createRuleCondition()
  295. val trueExpr = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral()
  296. trueExpr.value = "true"
  297. trueRule.condition.condition = trueExpr
  298. trueRule.statetransitionfunction = SemanticAdaptationFactory.eINSTANCE.createStateTransitionFunction()
  299. trueRule.outputfunction = SemanticAdaptationFactory.eINSTANCE.createCompositeOutputFunction()
  300. sa.in.rules.add(0, trueRule)
  301. rule = trueRule
  302. } else {
  303. Log.println("Existing rule with true condition found.")
  304. rule = sa.in.rules.head
  305. }
  306. return rule
  307. }
  308. def isTrueRule(DataRule rule){
  309. if (rule.condition.condition instanceof BoolLiteral){
  310. return (rule.condition.condition as BoolLiteral).value == "true"
  311. }
  312. return false
  313. }
  314. def addInVars(Adaptation sa, Map<Port, SingleParamDeclaration> inputPort2parameterDeclaration){
  315. Log.push("addInVars")
  316. var inputPort2InVarDeclaration = new HashMap<Port, SingleVarDeclaration>()
  317. for(inputPort : inputPort2parameterDeclaration.keySet){
  318. Log.println("Processing port " + inputPort.name)
  319. val paramDecl = inputPort2parameterDeclaration.get(inputPort)
  320. val varDeclarationName = getGeneratedInVarDeclarationName(inputPort)
  321. if (!varDeclarationExists(varDeclarationName, sa)){
  322. Log.println("Creating new input variable declaration " + varDeclarationName)
  323. val varDeclaration = addNewInputVarDeclaration(inputPort, paramDecl, sa)
  324. inputPort2InVarDeclaration.put(inputPort, varDeclaration)
  325. } else {
  326. Log.println("Input variable declaration " + varDeclarationName + " already exists.")
  327. }
  328. }
  329. Log.pop("addInVars")
  330. return inputPort2InVarDeclaration
  331. }
  332. def addNewInputVarDeclaration(Port externalInputPort, SingleParamDeclaration paramDecl, Adaptation sa) {
  333. if (sa.in === null){
  334. sa.in = SemanticAdaptationFactory.eINSTANCE.createInRulesBlock()
  335. }
  336. if (sa.in.globalInVars.size == 0){
  337. sa.in.globalInVars.add(SemanticAdaptationFactory.eINSTANCE.createDeclaration())
  338. }
  339. val newSingleVarDecl = SemanticAdaptationFactory.eINSTANCE.createSingleVarDeclaration()
  340. newSingleVarDecl.name = getGeneratedInVarDeclarationName(externalInputPort)
  341. newSingleVarDecl.type = externalInputPort.type
  342. val initValue = SemanticAdaptationFactory.eINSTANCE.createVariable()
  343. initValue.ref = paramDecl
  344. newSingleVarDecl.expr = initValue
  345. sa.in.globalInVars.head.declarations.add(newSingleVarDecl)
  346. Log.println("New input variable declaration created: " + newSingleVarDecl.name + " := " + paramDecl.name)
  347. return newSingleVarDecl
  348. }
  349. def varDeclarationExists(String invarName, Adaptation sa) {
  350. if (sa.in !== null){
  351. for (declarations : sa.in.globalInVars){
  352. for (decl : declarations.declarations){
  353. if (decl.name == invarName){
  354. return true
  355. }
  356. }
  357. }
  358. }
  359. return false
  360. }
  361. def getGeneratedInVarDeclarationName(Port externalInputPort) {
  362. return "stored__" + externalInputPort.name;
  363. }
  364. def genericDeclarationInferenceAlgorithm(Adaptation sa,
  365. (EObject)=>Object getField,
  366. (EObject, Object)=>void setField,
  367. (EObject)=>Object inferField
  368. ){
  369. Log.push("Running generic inference algorithm...")
  370. /*
  371. * Dumbest (and simplest) algorithm for this is a fixed point computation:
  372. * 1. Look for every var/port declaration
  373. * 2. If that var has a XXX already, nothing else to be done.
  374. * 3. If that var has no XXX declared, then
  375. * 3.1 If var/port has an initial value or connection, then
  376. * 3.1.1 If the initial_value/connection has a XXX declared, then var gets that XXX.
  377. * 3.1.2 Otherwise, nothing else to be done.
  378. * 3.2 If var/port has no initial value or connection then this either is a missing feature, or an error.
  379. * 3.3 If something has changed, go to 1. Otherwise, end.
  380. *
  381. * An extra set of instructions is there to push the element field information using connections and bindings.
  382. */
  383. var fixedPoint = false
  384. var unfieldedElementsCounter = 0
  385. while (! fixedPoint){
  386. fixedPoint = true
  387. unfieldedElementsCounter = 0
  388. Log.println("Inferring parameter fields...")
  389. for (paramDeclarations : sa.params) {
  390. for (paramDeclaration : paramDeclarations.declarations) {
  391. Log.println("Computing field for param " + paramDeclaration.name)
  392. if(getField.apply(paramDeclaration) !== null){
  393. Log.println("Already has been inferred: " + getField.apply(paramDeclaration))
  394. } else {
  395. Log.println("Has not been inferred yet.")
  396. if (tryInferAndAssignField(paramDeclaration, getField, setField, inferField)){
  397. fixedPoint = false
  398. } else {
  399. unfieldedElementsCounter++
  400. }
  401. }
  402. }
  403. }
  404. if(sa.inner !== null){
  405. if(sa.inner instanceof InnerFMUDeclarationFull){
  406. var innerFMUFull = sa.inner as InnerFMUDeclarationFull
  407. for(fmu : innerFMUFull.fmus){
  408. Log.println("Inferring port fields of FMU " + fmu.name)
  409. for (port : EcoreUtil2.getAllContentsOfType(fmu, Port)) {
  410. if(getField.apply(port) !== null){
  411. Log.println("Already has a field: " + getField.apply(port))
  412. } else {
  413. if (tryInferAndAssignField(port, getField, setField, inferField)){
  414. fixedPoint = false
  415. } else {
  416. unfieldedElementsCounter++
  417. }
  418. }
  419. }
  420. }
  421. if (innerFMUFull.connection.size > 0){
  422. Log.println("Inferring port fields using internal scenario bindings.")
  423. for (binding : innerFMUFull.connection){
  424. if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
  425. Log.println("Both ports have fields already.")
  426. } else {
  427. var inferredFieldAttempt = inferPortFieldViaConnection(binding, getField, setField, inferField)
  428. if (inferredFieldAttempt !== null){
  429. if (getField.apply(binding.src.port) === null){
  430. setField.apply(binding.src.port, inferredFieldAttempt)
  431. } else if (getField.apply(binding.tgt.port) === null){
  432. setField.apply(binding.tgt.port, inferredFieldAttempt)
  433. }
  434. fixedPoint = false
  435. unfieldedElementsCounter--
  436. Log.println("Got new field: " + inferredFieldAttempt)
  437. } else {
  438. Log.println("Cannot infer field from binding now.")
  439. }
  440. }
  441. }
  442. }
  443. } else {
  444. throw new Exception("Field inference only supported for InnerFMUDeclarationFull.")
  445. }
  446. }
  447. Log.println("Inferring external port fields...")
  448. var externalPorts = new LinkedList(sa.inports)
  449. externalPorts.addAll(sa.outports)
  450. for (port : externalPorts) {
  451. if (getField.apply(port) !== null){
  452. Log.println("Already has a field: " + getField.apply(port))
  453. if (pushPortField(port, getField, setField, inferField)){
  454. fixedPoint = false
  455. unfieldedElementsCounter--
  456. }
  457. } else {
  458. if (tryInferAndAssignField(port, getField, setField, inferField)){
  459. fixedPoint = false
  460. } else {
  461. unfieldedElementsCounter++
  462. }
  463. }
  464. }
  465. Log.println("Inferring all other declaration fields...")
  466. for (varDeclaration : EcoreUtil2.getAllContentsOfType(sa, SingleVarDeclaration)) {
  467. Log.println("Computing field for declaration " + varDeclaration.name)
  468. if(getField.apply(varDeclaration) !== null){
  469. Log.println("Already has a field: " + getField.apply(varDeclaration))
  470. } else {
  471. if (tryInferAndAssignField(varDeclaration, getField, setField, inferField)){
  472. fixedPoint = false
  473. } else {
  474. unfieldedElementsCounter++
  475. }
  476. }
  477. }
  478. Log.println("Ended iteration with unfielded elements remaining: " + unfieldedElementsCounter)
  479. } // while (! fixedPoint)
  480. Log.pop("Running generic inference algorithm... DONE")
  481. return unfieldedElementsCounter
  482. }
  483. def tryInferAndAssignField(EObject element,
  484. (EObject)=>Object getField,
  485. (EObject, Object)=>void setField,
  486. (EObject)=>Object inferField) {
  487. var inferredFieldAttempt = inferField.apply(element)
  488. if (inferredFieldAttempt !== null){
  489. setField.apply(element, inferredFieldAttempt)
  490. Log.println("Got new field: " + inferredFieldAttempt)
  491. return true
  492. } else {
  493. Log.println("Cannot infer field now.")
  494. return false
  495. }
  496. }
  497. def extractTypeFromExpression(Expression expression, String declarationName){
  498. if (expression instanceof IntLiteral){
  499. return "Integer"
  500. } else if (expression instanceof RealLiteral){
  501. return "Real"
  502. } else if (expression instanceof BoolLiteral){
  503. return "Bool"
  504. } else if (expression instanceof StringLiteral){
  505. return "String"
  506. } else if (expression instanceof Variable){
  507. var varRef = expression as Variable
  508. if (varRef.ref instanceof Port){
  509. var decl = varRef.ref as Port
  510. if (decl.type !== null){
  511. return decl.type
  512. }
  513. } else if(varRef.ref instanceof SingleParamDeclaration){
  514. var decl = varRef.ref as SingleParamDeclaration
  515. if (decl.type !== null){
  516. return decl.type
  517. }
  518. } else if(varRef.ref instanceof SingleVarDeclaration){
  519. var decl = varRef.ref as SingleVarDeclaration
  520. if (decl.type !== null){
  521. return decl.type
  522. }
  523. } else if(varRef.ref instanceof DeclaredParameter){
  524. throw new Exception("Type cannot be inferred for references to DeclaredParameter (for now). Please specify the explicit type of declaration " + declarationName)
  525. } else {
  526. throw new Exception("Unexpected kind of Variable expression found.")
  527. }
  528. } else if(expression instanceof BuiltinFunction){
  529. if (expression instanceof IsSet || expression instanceof Close){
  530. return "Bool"
  531. } else {
  532. return "Real"
  533. }
  534. } else {
  535. throw new Exception("Initial value for declaration " + declarationName + " must be literal or var ref for now. Got instead " + expression + ". If you want complex expressions, give it an explicit type.")
  536. }
  537. return null
  538. }
  539. def inferPortFieldViaConnection(Connection binding,
  540. (EObject)=>Object getField,
  541. (EObject, Object)=>void setField,
  542. (EObject)=>Object inferField
  543. ){
  544. var Object resultField = null
  545. if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
  546. throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
  547. } else if (getField.apply(binding.src.port) !== null){
  548. resultField = getField.apply(binding.src.port)
  549. Log.println("Target port "+ binding.tgt.port.name +" got new type: " + resultField)
  550. } else if (getField.apply(binding.tgt.port) !== null){
  551. resultField = getField.apply(binding.tgt.port)
  552. Log.println("Target port "+ binding.src.port.name +" got new type: " + resultField)
  553. }
  554. return resultField
  555. }
  556. def pushPortField(Port port,
  557. (EObject)=>Object getField,
  558. (EObject, Object)=>void setField,
  559. (EObject)=>Object inferField){
  560. var fieldInferred = false
  561. Log.println("Pushing field of port " + port.name + " to its bindings.")
  562. if(getField.apply(port) === null){
  563. Log.println("Has no field to be pushed.")
  564. throw new Exception("Wrong way of using this function. It assumes field is already inferred.")
  565. } else {
  566. Log.println("Pushing field: " + getField.apply(port))
  567. if(port.sourcedependency !== null){
  568. Log.println("Has a source dependency: " + port.sourcedependency.port.name)
  569. if(getField.apply(port.sourcedependency.port) === null){
  570. setField.apply(port.sourcedependency.port, getField.apply(port))
  571. Log.println("Port " + port.sourcedependency.port.name + " got new type: " + getField.apply(port.sourcedependency.port))
  572. fieldInferred = true
  573. } else {
  574. Log.println("Source port already has field.")
  575. }
  576. } else {
  577. Log.println("Has no source dependency.")
  578. }
  579. if (port.targetdependency !== null) {
  580. Log.println("Has a target dependency: " + port.targetdependency.port.name)
  581. if(getField.apply(port.targetdependency.port) === null){
  582. Log.println("Dependency has no field yet.")
  583. setField.apply(port.targetdependency.port, getField.apply(port))
  584. Log.println("Port " + port.targetdependency.port.name + " got new type: " + getField.apply(port.targetdependency.port))
  585. fieldInferred = true
  586. } else {
  587. Log.println("Target port already has field.")
  588. }
  589. } else {
  590. Log.println("Has no target dependency.")
  591. }
  592. }
  593. return fieldInferred
  594. }
  595. def getPortUnit(Port port){
  596. var unitInferred = false
  597. Log.println("Computing unit for port " + port.name)
  598. var Unity returnUnit = null
  599. if(port.unity !== null){
  600. throw new Exception("Wrong way of using this function. It assumes unit is not inferred yet.")
  601. } else {
  602. Log.println("Has no unit.")
  603. Log.println("Attempting to infer unit from bindings.")
  604. if(port.sourcedependency !== null){
  605. Log.println("Has a source dependency: " + port.sourcedependency.port.name)
  606. if(port.sourcedependency.port.unity === null){
  607. Log.println("Dependency has no unit yet.")
  608. } else {
  609. returnUnit = port.sourcedependency.port.unity
  610. Log.println("Got new unit: " + returnUnit)
  611. unitInferred = true
  612. }
  613. } else {
  614. Log.println("Has no source dependency.")
  615. }
  616. if (port.targetdependency !== null && !unitInferred) {
  617. Log.println("Has a target dependency: " + port.targetdependency.owner.name + "." + port.targetdependency.port.name)
  618. if(port.targetdependency.port.unity === null){
  619. Log.println("Dependency has no unit yet.")
  620. } else {
  621. returnUnit = port.targetdependency.port.unity
  622. Log.println("Got new unit: " + returnUnit)
  623. unitInferred = true
  624. }
  625. } else {
  626. Log.println("Has no target dependency, or unit has already been inferred from source dependency.")
  627. }
  628. }
  629. return returnUnit
  630. }
  631. def getPortType(Port port){
  632. var typeInferred = false
  633. Log.println("Computing type for port " + port.name)
  634. var String returnType = null
  635. if(port.type !== null){
  636. throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
  637. } else {
  638. Log.println("Has no type.")
  639. Log.println("Attempting to infer type from units.")
  640. if (port.unity !== null){
  641. returnType = "Real"
  642. Log.println("Got new type: " + returnType)
  643. typeInferred = true
  644. } else {
  645. Log.println("Attempting to infer type from bindings.")
  646. if(port.sourcedependency !== null){
  647. Log.println("Has a source dependency: " + port.sourcedependency.port.name)
  648. if(port.sourcedependency.port.type === null){
  649. Log.println("Dependency has no type yet.")
  650. } else {
  651. returnType = port.sourcedependency.port.type
  652. Log.println("Got new type: " + returnType)
  653. typeInferred = true
  654. }
  655. } else {
  656. Log.println("Has no source dependency.")
  657. }
  658. if (port.targetdependency !== null && !typeInferred) {
  659. Log.println("Has a target dependency: " + port.targetdependency.owner.name + "." + port.targetdependency.port.name)
  660. if(port.targetdependency.port.type === null){
  661. //println("Port object: " + port.targetdependency.port)
  662. Log.println("Dependency has no type yet.")
  663. } else {
  664. returnType = port.targetdependency.port.type
  665. Log.println("Got new type: " + returnType)
  666. typeInferred = true
  667. }
  668. } else {
  669. Log.println("Has no target dependency, or type has already been inferred from source dependency.")
  670. }
  671. }
  672. }
  673. return returnType
  674. }
  675. def addInPorts(Adaptation sa) {
  676. Log.push("Adding input ports...")
  677. for (port : getAllInnerFMUInputPortDeclarations(sa)){
  678. var parentFMU = port.eContainer as InnerFMU
  679. Log.println("Checking if port " + parentFMU.name + "." + port.name + " has incoming connections")
  680. if (! hasConnection(port, sa, true)){
  681. Log.println("Port " + parentFMU.name + "." + port.name + " has no incoming connections.")
  682. val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name)
  683. if (findExternalPortByName(sa, externalPortName) === null){
  684. var newExternalPort = createExternalInputPortDeclarationFromInnerPort(port, parentFMU, sa)
  685. Log.println("External port " + newExternalPort.name + " created.")
  686. newExternalPort.bindExternalInputPortTo(parentFMU, port)
  687. Log.println("External port " + newExternalPort.name + " bound to port " + parentFMU.name + "." + port.name)
  688. } else {
  689. Log.println("Error: External port " + externalPortName + " already declared.")
  690. throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it to avoid clashes.")
  691. }
  692. } else {
  693. Log.println("Port " + parentFMU.name + "." + port.name + " has an incoming connection.")
  694. }
  695. }
  696. Log.pop("Adding input ports... DONE")
  697. }
  698. def bindExternalInputPortTo(Port externalInputPort, InnerFMU internalPortParent, Port internalPort) {
  699. externalInputPort.targetdependency = SemanticAdaptationFactory.eINSTANCE.createSpecifiedPort()
  700. externalInputPort.targetdependency.owner = internalPortParent
  701. externalInputPort.targetdependency.port = internalPort
  702. }
  703. def createExternalInputPortDeclarationFromInnerPort(Port port, FMU parent, Adaptation sa) {
  704. var externalInputPort = SemanticAdaptationFactory.eINSTANCE.createPort()
  705. externalInputPort.name = createExternalPortNameFromInternalPort(parent.name, port.name)
  706. externalInputPort.type = port.type
  707. externalInputPort.unity = EcoreUtil2.copy(port.unity)
  708. sa.inports.add(externalInputPort)
  709. return externalInputPort
  710. }
  711. def findExternalPortByName(Adaptation adaptation, String name) {
  712. for (externalInputPort : adaptation.inports){
  713. if (externalInputPort.name == name){
  714. return externalInputPort
  715. }
  716. }
  717. return null
  718. }
  719. def findExternalPortByTargetDependency(Adaptation sa, Port targetDependency) {
  720. for (externalInputPort : sa.inports){
  721. if (externalInputPort.targetdependency !== null && externalInputPort.targetdependency.port == targetDependency){
  722. return externalInputPort
  723. }
  724. }
  725. return null
  726. }
  727. def hasConnection(Port port, Adaptation adaptation, Boolean checkForIncomming) {
  728. var result = false
  729. if ( (checkForIncomming && port.sourcedependency !== null) ||
  730. (! checkForIncomming && port.targetdependency !== null)
  731. ){
  732. result = true
  733. } else {
  734. if (port.eContainer instanceof InnerFMU){
  735. var innerScenarioDeclaration = EcoreUtil2.getContainerOfType(port, InnerFMUDeclaration)
  736. if (innerScenarioDeclaration instanceof InnerFMUDeclarationFull){
  737. var innerScenarioWithCoupling = innerScenarioDeclaration as InnerFMUDeclarationFull
  738. if (innerScenarioWithCoupling.connection.size > 0){
  739. for (connection : innerScenarioWithCoupling.connection ){
  740. if ( (checkForIncomming && connection.tgt.port == port)){
  741. var parentFMU = port.eContainer as InnerFMU
  742. var sourceFMU = connection.src.port.eContainer as InnerFMU
  743. Log.println("Port " + parentFMU.name + "." + port.name + " has an incoming connection from internal port " + sourceFMU.name + "." + connection.src.port.name)
  744. result = true
  745. } else if (!checkForIncomming && connection.src.port == port) {
  746. var parentFMU = port.eContainer as InnerFMU
  747. var targetFMU = connection.tgt.port.eContainer as InnerFMU
  748. Log.println("Port " + parentFMU.name + "." + port.name + " has an outgoing connection to internal port " + targetFMU.name + "." + connection.tgt.port.name)
  749. result = true
  750. }
  751. }
  752. }
  753. }
  754. for (externalInputPort : adaptation.inports.filter[p | (checkForIncomming && p.targetdependency !== null) || (!checkForIncomming && p.sourcedependency !== null) ]){
  755. if (checkForIncomming && externalInputPort.targetdependency.port == port){
  756. var parentFMU = port.eContainer as InnerFMU
  757. Log.println("Port " + parentFMU.name + "." + port.name + " has an incoming connection from external port " + externalInputPort.name)
  758. result = true
  759. } else if ( !checkForIncomming && externalInputPort.sourcedependency.port == port){
  760. var parentFMU = port.eContainer as InnerFMU
  761. Log.println("Port " + parentFMU.name + "." + port.name + " has an outgoing connection to external port " + externalInputPort.name)
  762. result = true
  763. }
  764. }
  765. }
  766. }
  767. return result
  768. }
  769. def getAllInnerFMUInputPortDeclarations(Adaptation sa){
  770. return mapAllInnerFMUs(sa, [fmu | fmu.inports]);
  771. }
  772. def getAllInnerFMUOutputPortDeclarations(Adaptation sa){
  773. return mapAllInnerFMUs(sa, [fmu | fmu.outports]);
  774. }
  775. def <T> List<T> mapAllInnerFMUs(Adaptation sa, (InnerFMU)=>List<T> map){
  776. var result = new LinkedList()
  777. if(sa.inner !== null){
  778. if(sa.inner instanceof InnerFMUDeclarationFull){
  779. var innerFMUFull = sa.inner as InnerFMUDeclarationFull
  780. for(fmu : innerFMUFull.fmus){
  781. result.addAll(map.apply(fmu))
  782. }
  783. } else {
  784. throw new Exception("Only support for InnerFMUDeclarationFull.")
  785. }
  786. }
  787. return result;
  788. }
  789. def addInParams(Adaptation sa) {
  790. Log.push("Adding input parameters...")
  791. val PARAM_PREFIX = "INIT_"
  792. var inputPort2parameterDeclaration = new HashMap<Port, SingleParamDeclaration>(sa.inports.size)
  793. for (inputPortDeclaration : sa.inports) {
  794. Log.println("Generating parameter for port " + inputPortDeclaration.name)
  795. var paramname = PARAM_PREFIX + inputPortDeclaration.name.toUpperCase()
  796. if (paramAlreadyDeclared(paramname, sa)){
  797. Log.println("Parameter " + paramname + " already declared for port " + inputPortDeclaration.name)
  798. } else {
  799. Log.println("Declaring new parameter " + paramname + " for port " + inputPortDeclaration.name)
  800. var paramDeclaration = addNewParamDeclaration(paramname, inputPortDeclaration, sa)
  801. inputPort2parameterDeclaration.put(inputPortDeclaration, paramDeclaration)
  802. }
  803. }
  804. Log.pop("Adding input parameters... DONE")
  805. return inputPort2parameterDeclaration
  806. }
  807. def addNewParamDeclaration(String name, Port fromPort, Adaptation sa) {
  808. var factory = SemanticAdaptationFactory.eINSTANCE
  809. var paramDeclaration = factory.createSingleParamDeclaration()
  810. paramDeclaration.name = name
  811. paramDeclaration.type = fromPort.type
  812. paramDeclaration.expr = getDefaultTypeExpression(paramDeclaration.type)
  813. if (sa.params.size == 0){
  814. sa.params.add(factory.createParamDeclarations())
  815. }
  816. sa.params.head.declarations.add(paramDeclaration)
  817. return paramDeclaration
  818. }
  819. def getDefaultTypeExpression(String type) {
  820. switch (type) {
  821. case "Integer": {
  822. val result = SemanticAdaptationFactory.eINSTANCE.createIntLiteral
  823. result.value = 0
  824. return result
  825. }
  826. case "Real": {
  827. val result = SemanticAdaptationFactory.eINSTANCE.createRealLiteral
  828. result.value = 0.0f
  829. return result
  830. }
  831. case "Bool": {
  832. val result = SemanticAdaptationFactory.eINSTANCE.createBoolLiteral
  833. result.value = "false"
  834. return result
  835. }
  836. case "String": {
  837. val result = SemanticAdaptationFactory.eINSTANCE.createStringLiteral
  838. result.value = ""
  839. return result
  840. }
  841. default: {
  842. throw new Exception("Unexpected type.")
  843. }
  844. }
  845. }
  846. def paramAlreadyDeclared(String name, Adaptation sa) {
  847. for(paramDeclarations : sa.params){
  848. for(paramDeclaration : paramDeclarations.declarations){
  849. if(paramDeclaration.name == name){
  850. return true
  851. }
  852. }
  853. }
  854. return false
  855. }
  856. def addOutPorts(Adaptation sa) {
  857. Log.push("Adding output ports...")
  858. for (port : getAllInnerFMUOutputPortDeclarations(sa)){
  859. var parentFMU = port.eContainer as InnerFMU
  860. Log.println("Checking if port " + parentFMU.name + "." + port.name + " has outgoing connections")
  861. if (! hasConnection(port, sa, false)){
  862. Log.println("Port " + parentFMU.name + "." + port.name + " has no outgoing connections.")
  863. // TODO Continue here.
  864. val externalPortName = createExternalPortNameFromInternalPort(parentFMU.name, port.name)
  865. if (findExternalPortByName(sa, externalPortName) === null){
  866. var newExternalPort = createExternalInputPortDeclarationFromInnerPort(port, parentFMU, sa)
  867. Log.println("External port " + newExternalPort.name + " created.")
  868. newExternalPort.bindExternalInputPortTo(parentFMU, port)
  869. Log.println("External port " + newExternalPort.name + " bound to port " + parentFMU.name + "." + port.name)
  870. } else {
  871. Log.println("Error: External port " + externalPortName + " already declared.")
  872. throw new Exception("Error: External port " + externalPortName + " already declared. Please rename it to avoid clashes.")
  873. }
  874. } else {
  875. Log.println("Port " + parentFMU.name + "." + port.name + " has an incoming connection.")
  876. }
  877. }
  878. Log.pop("Adding output ports... DONE")
  879. }
  880. }