SemanticAdaptationCanonicalGenerator.xtend 31 KB

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