OMCompiler/Compiler/NFFrontEnd/NFExpandableConnectors.mo
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | encapsulated package NFExpandableConnectors | ||
| 37 | |||
| 38 | public | ||
| 39 | import FlatModel = NFFlatModel; | ||
| 40 | import Connections = NFConnections; | ||
| 41 | |||
| 42 | protected | ||
| 43 | import Array; | ||
| 44 | import Binding = NFBinding; | ||
| 45 | import ComplexType = NFComplexType; | ||
| 46 | import ComponentRef = NFComponentRef; | ||
| 47 | import Connection = NFConnection; | ||
| 48 | import ConnectionSets = NFConnectionSets.ConnectionSets; | ||
| 49 | import Connector = NFConnector; | ||
| 50 | import ElementSource; | ||
| 51 | import Error; | ||
| 52 | import Expression = NFExpression; | ||
| 53 | import MetaModelica.Dangerous.listReverseInPlace; | ||
| 54 | import Class = NFClass; | ||
| 55 | import NFClassTree.ClassTree; | ||
| 56 | import Component = NFComponent; | ||
| 57 | import NFInstNode.InstNode; | ||
| 58 | import NFInstNode; | ||
| 59 | import NFPrefixes.ConnectorType; | ||
| 60 | import NFPrefixes.Visibility; | ||
| 61 | import NFTypeCheck.MatchKind; | ||
| 62 | import Prefixes = NFPrefixes; | ||
| 63 | import TypeCheck = NFTypeCheck; | ||
| 64 | import Type = NFType; | ||
| 65 | import Typing = NFTyping; | ||
| 66 | import UnorderedSet; | ||
| 67 | import Util; | ||
| 68 | import Variable = NFVariable; | ||
| 69 | |||
| 70 | public | ||
| 71 | function elaborate | ||
| 72 | input output FlatModel flatModel; | ||
| 73 | input output Connections connections; | ||
| 74 | protected | ||
| 75 | list<Connection> expandable_conns, undeclared_conns, conns; | ||
| 76 | list<Variable> vars; | ||
| 77 | ConnectionSets.Sets csets; | ||
| 78 | array<list<Connector>> csets_array; | ||
| 79 | algorithm | ||
| 80 | // Sort the connections based on whether they involve expandable connectors, | ||
| 81 | // undeclared/potentially present connectors, or only normal connectors. | ||
| 82 | 1573 | (expandable_conns, undeclared_conns, conns) := sortConnections(connections.connections); | |
| 83 | |||
| 84 | // Don't do anything if there aren't any expandable connectors in the model. | ||
| 85 |
4/4✓ Branch 0 taken 1568 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1562 times.
✓ Branch 3 taken 6 times.
|
1573 | if listEmpty(expandable_conns) and listEmpty(undeclared_conns) then |
| 86 | 1562 | return; | |
| 87 | end if; | ||
| 88 | |||
| 89 | // Create a graph from the connections. Expandable connectors connect to | ||
| 90 | // expandable connectors, while undeclared/potentially present connectors connect | ||
| 91 | // to the expandable connector they belong to. | ||
| 92 | 11 | csets := ConnectionSets.emptySets(listLength(expandable_conns) + listLength(undeclared_conns)); | |
| 93 | 11 | csets := addExpandableConnectorsToSets(expandable_conns, csets); | |
| 94 | 11 | (undeclared_conns, csets) := List.mapFold(undeclared_conns, addExpandableConnectorElementToSets, csets); | |
| 95 | |||
| 96 | // Extract the sets of connected connectors. | ||
| 97 | 11 | csets_array := ConnectionSets.extractSets(csets); | |
| 98 | |||
| 99 | //for set in csets_array loop | ||
| 100 | // print("Expandable connection set:\n"); | ||
| 101 | // print(List.toString(set, Connector.toString, "", "{", ", ", "}", true) + "\n"); | ||
| 102 | //end for; | ||
| 103 | |||
| 104 | // Augment the expandable connectors with the necessary elements, mark | ||
| 105 | // connected potentially present variables as present, and add the | ||
| 106 | // created variables to the flat model. | ||
| 107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | vars := flatModel.variables; |
| 108 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 11 times.
|
33 | for set in csets_array loop |
| 109 | 22 | vars := elaborateExpandableSet(set, vars); | |
| 110 | end for; | ||
| 111 | |||
| 112 | // Update the connections and put them back in the list of connections. | ||
| 113 | 11 | conns := List.fold(undeclared_conns, updateUndeclaredConnection, conns); | |
| 114 | 11 | conns := List.fold(expandable_conns, updateExpandableConnection, conns); | |
| 115 | 11 | connections.connections := conns; | |
| 116 | |||
| 117 | // Update the attributes of potentially present variables so that they have | ||
| 118 | // the same attributes as their node. Their connector type will have changed | ||
| 119 | // if they've been marked as present. | ||
| 120 |
4/4✓ Branch 0 taken 1214 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1214 times.
✓ Branch 3 taken 11 times.
|
1225 | vars := list(updatePotentiallyPresentVariable(v) for v in vars); |
| 121 | 11 | flatModel.variables := vars; | |
| 122 | end elaborate; | ||
| 123 | |||
| 124 | protected | ||
| 125 | |||
| 126 | function sortConnections | ||
| 127 | "Sorts the connections into different categories of connectors based on | ||
| 128 | whether they involve expandable connectors, undeclared/potentially present | ||
| 129 | connector, or only normal connectors." | ||
| 130 | input list<Connection> conns; | ||
| 131 | output list<Connection> expandableConnections = {}; | ||
| 132 | output list<Connection> undeclaredConnections = {}; | ||
| 133 | output list<Connection> normalConnections = {}; | ||
| 134 | protected | ||
| 135 | Connector c1, c2; | ||
| 136 | Boolean is_undeclared1, is_undeclared2, is_expandable1, is_expandable2; | ||
| 137 | algorithm | ||
| 138 |
2/2✓ Branch 0 taken 13948 times.
✓ Branch 1 taken 1573 times.
|
15521 | for conn in conns loop |
| 139 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13948 times.
|
13948 | Connection.CONNECTION(lhs = c1, rhs = c2) := conn; |
| 140 | |||
| 141 |
4/4✓ Branch 1 taken 13942 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 13937 times.
|
13948 | is_undeclared1 := ConnectorType.isUndeclared(c1.cty) or ConnectorType.isPotentiallyPresent(c1.cty); |
| 142 |
4/4✓ Branch 1 taken 13894 times.
✓ Branch 2 taken 54 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 13878 times.
|
13948 | is_undeclared2 := ConnectorType.isUndeclared(c2.cty) or ConnectorType.isPotentiallyPresent(c2.cty); |
| 143 | 13948 | is_expandable1 := ConnectorType.isExpandable(c1.cty); | |
| 144 | 13948 | is_expandable2 := ConnectorType.isExpandable(c2.cty); | |
| 145 | |||
| 146 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 13938 times.
|
13948 | if is_expandable1 or is_expandable2 then |
| 147 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if is_expandable1 and is_expandable2 then |
| 148 | expandableConnections := conn :: expandableConnections; | ||
| 149 | else | ||
| 150 | // An expandable connector may only connect to another expandable connector. | ||
| 151 | ✗ | Error.addSourceMessageAndFail(Error.EXPANDABLE_NON_EXPANDABLE_CONNECTION, | |
| 152 | {Connector.toString(if is_expandable1 then c1 else c2), | ||
| 153 | Connector.toString(if is_expandable1 then c2 else c1)}, | ||
| 154 | Connector.getInfo(c1)); | ||
| 155 | end if; | ||
| 156 | elseif is_undeclared1 or is_undeclared2 then | ||
| 157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
|
81 | if is_undeclared1 and is_undeclared2 then |
| 158 | // Both sides can't be undeclared, one must be a declared component. | ||
| 159 | ✗ | Error.addSourceMessageAndFail(Error.UNDECLARED_CONNECTION, | |
| 160 | {Connector.toString(c1), Connector.toString(c2)}, Connector.getInfo(c1)); | ||
| 161 | else | ||
| 162 | undeclaredConnections := conn :: undeclaredConnections; | ||
| 163 | end if; | ||
| 164 | else | ||
| 165 | normalConnections := conn :: normalConnections; | ||
| 166 | end if; | ||
| 167 | end for; | ||
| 168 | |||
| 169 | 1573 | normalConnections := listReverseInPlace(normalConnections); | |
| 170 | end sortConnections; | ||
| 171 | |||
| 172 | function addExpandableConnectorsToSets | ||
| 173 | input list<Connection> conns; | ||
| 174 | input output ConnectionSets.Sets csets; | ||
| 175 | protected | ||
| 176 | Connector c1, c2; | ||
| 177 | algorithm | ||
| 178 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 14 times.
|
32 | for conn in conns loop |
| 179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | Connection.CONNECTION(lhs = c1, rhs = c2) := conn; |
| 180 | 18 | csets := addConnectionToSets(c1, c2, csets); | |
| 181 | 18 | csets := addNestedExpandableConnectorsToSets(c1, c2, csets); | |
| 182 | end for; | ||
| 183 | end addExpandableConnectorsToSets; | ||
| 184 | |||
| 185 | function addNestedExpandableConnectorsToSets | ||
| 186 | input Connector c1; | ||
| 187 | input Connector c2; | ||
| 188 | input output ConnectionSets.Sets csets; | ||
| 189 | protected | ||
| 190 | list<Connector> ecl1, ecl2; | ||
| 191 | Option<Connector> oec; | ||
| 192 | list<Connection> conns = {}; | ||
| 193 | algorithm | ||
| 194 | 18 | ecl1 := getExpandableConnectorsInConnector(c1); | |
| 195 | 18 | ecl2 := getExpandableConnectorsInConnector(c2); | |
| 196 | |||
| 197 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
18 | if listEmpty(ecl1) and listEmpty(ecl2) then |
| 198 | 15 | return; | |
| 199 | end if; | ||
| 200 | |||
| 201 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | for ec1 in ecl1 loop |
| 202 | 8 | (ecl2, oec) := List.deleteMemberOnTrue(ec1, ecl2, Connector.isNodeNameEqual); | |
| 203 | |||
| 204 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | if isSome(oec) then |
| 205 | 8 | conns := Connection.CONNECTION(ec1, Util.getOption(oec)) :: conns; | |
| 206 | end if; | ||
| 207 | end for; | ||
| 208 | |||
| 209 | 3 | csets := addExpandableConnectorsToSets(conns, csets); | |
| 210 | end addNestedExpandableConnectorsToSets; | ||
| 211 | |||
| 212 | function getExpandableConnectorsInConnector | ||
| 213 | input Connector c1; | ||
| 214 | output list<Connector> ecl; | ||
| 215 | protected | ||
| 216 | list<NFInstNode.ScopeRef> nodes; | ||
| 217 | InstNode n; | ||
| 218 | ComponentRef par_name, name; | ||
| 219 | Type ty; | ||
| 220 | algorithm | ||
| 221 | ecl := match c1 | ||
| 222 | case Connector.CONNECTOR(name = par_name, ty = Type.COMPLEX( | ||
| 223 | complexTy = ComplexType.EXPANDABLE_CONNECTOR(expandableConnectors = nodes))) | ||
| 224 | algorithm | ||
| 225 | ecl := {}; | ||
| 226 | |||
| 227 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 36 times.
|
52 | for n_ref in nodes loop |
| 228 | 16 | n := InstNode.borrow(n_ref); | |
| 229 | 16 | ty := InstNode.getType(n); | |
| 230 | 16 | name := ComponentRef.prefixCref(n, ty, {}, par_name); | |
| 231 | 16 | ecl := Connector.fromCref(name, ty, ElementSource.createElementSource(InstNode.info(n))) :: ecl; | |
| 232 | end for; | ||
| 233 | then | ||
| 234 | ecl; | ||
| 235 | |||
| 236 | else {}; | ||
| 237 | end match; | ||
| 238 | end getExpandableConnectorsInConnector; | ||
| 239 | |||
| 240 | function addExpandableConnectorElementToSets | ||
| 241 | input output Connection conn; | ||
| 242 | input output ConnectionSets.Sets csets; | ||
| 243 | protected | ||
| 244 | Connector c1, c2, c, ec; | ||
| 245 | algorithm | ||
| 246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
|
81 | Connection.CONNECTION(lhs = c1, rhs = c2) := conn; |
| 247 | |||
| 248 | // Figure out which connector to add, and create a virtual connector if necessary. | ||
| 249 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 75 times.
|
81 | if ConnectorType.isUndeclared(c1.cty) then |
| 250 | 6 | c1 := makeVirtualConnector(c1, c2); | |
| 251 | 6 | conn := Connection.CONNECTION(c1, c2); | |
| 252 | c := c1; | ||
| 253 | elseif ConnectorType.isUndeclared(c2.cty) then | ||
| 254 | 54 | c2 := makeVirtualConnector(c2, c1); | |
| 255 | 54 | conn := Connection.CONNECTION(c1, c2); | |
| 256 | c := c2; | ||
| 257 | else | ||
| 258 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 5 times.
|
21 | c := if ConnectorType.isPotentiallyPresent(c1.cty) then c1 else c2; |
| 259 | end if; | ||
| 260 | |||
| 261 | // Create a parent connector for the undeclared/potentially present connector, i.e. the expandable | ||
| 262 | // connector it should be added to. The type here is wrong, but it doesn't matter. | ||
| 263 | 81 | ec := Connector.CONNECTOR(ComponentRef.rest(c.name), c.ty, c.face, ConnectorType.EXPANDABLE, c.source); | |
| 264 | |||
| 265 | // Add a connection between the undeclared/potentially present connector and the expandable connector. | ||
| 266 | 81 | csets := addConnectionToSets(c, ec, csets); | |
| 267 | end addExpandableConnectorElementToSets; | ||
| 268 | |||
| 269 | function addConnectionToSets | ||
| 270 | input Connector c1; | ||
| 271 | input Connector c2; | ||
| 272 | input output ConnectionSets.Sets csets; | ||
| 273 | algorithm | ||
| 274 | // The connection sets are not used to represent actual connections here, only | ||
| 275 | // to keep track of which expandable connectors that are associated. So to | ||
| 276 | // make sure we only get one instance of each expandable connector in the sets | ||
| 277 | // we make sure the face of all the connectors we add is the same. | ||
| 278 | 99 | csets := ConnectionSets.merge(Connector.setOutside(c1), Connector.setOutside(c2), csets); | |
| 279 | end addConnectionToSets; | ||
| 280 | |||
| 281 | function makeVirtualConnector | ||
| 282 | input Connector virtualConnector; | ||
| 283 | input Connector normalConnector; | ||
| 284 | output Connector newConnector; | ||
| 285 | protected | ||
| 286 | ComponentRef virtual_cref, normal_cref; | ||
| 287 | Type ty; | ||
| 288 | InstNode node; | ||
| 289 | algorithm | ||
| 290 | 60 | virtual_cref := virtualConnector.name; | |
| 291 | 60 | normal_cref := normalConnector.name; | |
| 292 | 60 | ty := normalConnector.ty; | |
| 293 | |||
| 294 | // TODO: Update the virtual connector with the created node. | ||
| 295 | 60 | node := ComponentRef.node(normal_cref); | |
| 296 | 60 | node := InstNode.clone(node); | |
| 297 | 60 | node := InstNode.rename(ComponentRef.firstName(virtual_cref), node); | |
| 298 | 60 | node := InstNode.setParent(ComponentRef.node(ComponentRef.rest(virtual_cref)), node); | |
| 299 | 60 | node := InstNode.componentApply(node, Component.setType, ty); | |
| 300 | 60 | virtual_cref := ComponentRef.prefixCref(node, ty, {}, ComponentRef.rest(virtual_cref)); | |
| 301 | // TODO: This needs more work, the new connector might be a complex connector. | ||
| 302 | 60 | newConnector := Connector.CONNECTOR(virtual_cref, ty, virtualConnector.face, | |
| 303 | virtualConnector.cty, virtualConnector.source); | ||
| 304 | end makeVirtualConnector; | ||
| 305 | |||
| 306 | function elaborateExpandableSet | ||
| 307 | input list<Connector> set; | ||
| 308 | input output list<Variable> vars; | ||
| 309 | protected | ||
| 310 | UnorderedSet<Connector> exp_set; | ||
| 311 | list<Connector> exp_conns = {}, exp_set_lst; | ||
| 312 | algorithm | ||
| 313 | 22 | exp_set := UnorderedSet.new(hashConnector, Connector.isNodeNameEqual); | |
| 314 | |||
| 315 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 22 times.
|
142 | for c in set loop |
| 316 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 80 times.
|
120 | if ConnectorType.isExpandable(c.cty) then |
| 317 | exp_conns := c :: exp_conns; | ||
| 318 | elseif ConnectorType.isUndeclared(c.cty) or ConnectorType.isPotentiallyPresent(c.cty) then | ||
| 319 | 80 | UnorderedSet.add(c, exp_set); | |
| 320 | 80 | markComponentPresent(ComponentRef.node(Connector.name(c))); | |
| 321 | end if; | ||
| 322 | end for; | ||
| 323 | |||
| 324 | 22 | exp_set_lst := UnorderedSet.toList(exp_set); | |
| 325 | |||
| 326 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 22 times.
|
62 | for ec in exp_conns loop |
| 327 | 40 | vars := augmentExpandableConnector(ec, exp_set_lst, vars); | |
| 328 | end for; | ||
| 329 | end elaborateExpandableSet; | ||
| 330 | |||
| 331 | function markComponentPresent | ||
| 332 | input InstNode node; | ||
| 333 | protected | ||
| 334 | Component comp; | ||
| 335 | ConnectorType.Type cty; | ||
| 336 | Class cls; | ||
| 337 | algorithm | ||
| 338 | 152 | comp := InstNode.component(node); | |
| 339 | 152 | cty := Component.connectorType(comp); | |
| 340 | |||
| 341 |
2/2✓ Branch 1 taken 80 times.
✓ Branch 2 taken 72 times.
|
152 | if ConnectorType.isPotentiallyPresent(cty) then |
| 342 | 72 | cty := ConnectorType.setPresent(cty); | |
| 343 | 72 | comp := Component.setConnectorType(cty, comp); | |
| 344 | 72 | InstNode.updateComponent(comp, node); | |
| 345 | |||
| 346 | // Also mark the component's children as present. | ||
| 347 |
2/2✓ Branch 2 taken 71 times.
✓ Branch 3 taken 1 time.
|
72 | if Type.isComplex(Component.getType(comp)) then |
| 348 | 1 | cls := InstNode.getClass(Component.classInstance(comp)); | |
| 349 | 1 | ClassTree.applyComponents(Class.classTree(cls), markComponentPresent); | |
| 350 | end if; | ||
| 351 | end if; | ||
| 352 | end markComponentPresent; | ||
| 353 | |||
| 354 | function augmentExpandableConnector | ||
| 355 | input Connector conn; | ||
| 356 | input list<Connector> expandableSet; | ||
| 357 | input output list<Variable> vars; | ||
| 358 | protected | ||
| 359 | ComponentRef exp_name, elem_name; | ||
| 360 | InstNode exp_node, comp_node, cls_node, node; | ||
| 361 | Class cls; | ||
| 362 | ClassTree cls_tree; | ||
| 363 | list<InstNode> nodes = {}; | ||
| 364 | Type ty; | ||
| 365 | ComplexType complex_ty; | ||
| 366 | algorithm | ||
| 367 | 40 | exp_name := Connector.name(conn); | |
| 368 | 40 | exp_node := ComponentRef.node(exp_name); | |
| 369 | |||
| 370 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
|
40 | if InstNode.isName(exp_node) then |
| 371 | ✗ | Error.addInternalError( | |
| 372 | "Augmenting a virtual element in an expandable connector is not yet supported.", | ||
| 373 | Connector.getInfo(conn)); | ||
| 374 | ✗ | fail(); | |
| 375 | end if; | ||
| 376 | |||
| 377 | 40 | cls_node := InstNode.classScope(exp_node); | |
| 378 | 40 | cls_node := InstNode.clone(cls_node); | |
| 379 | 40 | cls := InstNode.getClass(cls_node); | |
| 380 | 40 | cls_tree := Class.classTree(cls); | |
| 381 | |||
| 382 | // Go through the union of elements the expandable connector should have. | ||
| 383 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 40 times.
|
172 | for c in expandableSet loop |
| 384 | 132 | elem_name := Connector.name(c); | |
| 385 | 132 | node := ComponentRef.node(elem_name); | |
| 386 | |||
| 387 | try | ||
| 388 | 132 | comp_node := ClassTree.lookupElement(InstNode.name(node), cls_tree); | |
| 389 | else | ||
| 390 | comp_node := InstNode.EMPTY_NODE(); | ||
| 391 | end try; | ||
| 392 | |||
| 393 |
2/2✓ Branch 1 taken 62 times.
✓ Branch 2 taken 70 times.
|
132 | if InstNode.isEmpty(comp_node) then |
| 394 | // If the element doesn't already exist, add it to the list of elements to be | ||
| 395 | // added to the connector. | ||
| 396 | 62 | nodes := node :: nodes; | |
| 397 | 62 | ty := c.ty; | |
| 398 | 62 | elem_name := ComponentRef.prefixCref(node, ty, {}, exp_name); | |
| 399 | 62 | vars := createVirtualVariables(elem_name, ty, ElementSource.getInfo(c.source), vars); | |
| 400 | else | ||
| 401 | 70 | comp_node := InstNode.resolveInner(comp_node); | |
| 402 | |||
| 403 |
1/2✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
|
70 | if InstNode.isComponent(comp_node) then |
| 404 | // If the element already exists and is a potentially present component, | ||
| 405 | // change it to be present. | ||
| 406 | 70 | markComponentPresent(comp_node); | |
| 407 | else | ||
| 408 | ✗ | Error.addInternalError(getInstanceName() + " got non-component element", sourceInfo()); | |
| 409 | end if; | ||
| 410 | end if; | ||
| 411 | end for; | ||
| 412 | |||
| 413 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 28 times.
|
40 | if not listEmpty(nodes) then |
| 414 | 12 | cls_tree := ClassTree.addElementsToFlatTree(nodes, cls_tree); | |
| 415 | 12 | cls := Class.setClassTree(cls_tree, cls); | |
| 416 | end if; | ||
| 417 | |||
| 418 | // Create a normal non-expandable complex type for the augmented expandable connector. | ||
| 419 | 40 | complex_ty := Typing.makeConnectorType(cls_tree, isExpandable = false); | |
| 420 | 40 | ty := Type.COMPLEX(InstNode.identityCell(cls_node), complex_ty); | |
| 421 | 40 | ty := Type.liftArrayLeftList(ty, Type.arrayDims(InstNode.getType(exp_node))); | |
| 422 | 40 | cls := Class.setType(ty, cls); | |
| 423 | 40 | InstNode.updateClass(cls, cls_node); | |
| 424 | 40 | InstNode.componentApply(exp_node, Component.setType, ty); | |
| 425 | end augmentExpandableConnector; | ||
| 426 | |||
| 427 | function createVirtualVariables | ||
| 428 | input ComponentRef connectorName; | ||
| 429 | input Type connectorType; | ||
| 430 | input SourceInfo info; | ||
| 431 | input output list<Variable> vars; | ||
| 432 | protected | ||
| 433 | Variable var; | ||
| 434 | ComponentRef name; | ||
| 435 | Type ty; | ||
| 436 | algorithm | ||
| 437 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 72 times.
|
82 | if Type.isComplex(connectorType) then |
| 438 |
2/2✓ Branch 2 taken 20 times.
✓ Branch 3 taken 10 times.
|
40 | for comp in Type.complexComponents(connectorType) loop |
| 439 | 20 | ty := InstNode.getType(comp); | |
| 440 | 20 | name := ComponentRef.prefixCref(comp, ty, {}, connectorName); | |
| 441 | 20 | vars := createVirtualVariables(name, ty, info, vars); | |
| 442 | end for; | ||
| 443 | else | ||
| 444 | 72 | var := Variable.VARIABLE(connectorName, connectorType, NFBinding.EMPTY_BINDING, | |
| 445 | Visibility.PUBLIC, NFAttributes.AUGMENTED_ATTR, {}, {}, | ||
| 446 | SCode.COMMENT(NONE(), SOME("variable added to expandable connector")), | ||
| 447 | info, NFBackendExtension.DUMMY_BACKEND_INFO); | ||
| 448 | vars := var :: vars; | ||
| 449 | end if; | ||
| 450 | end createVirtualVariables; | ||
| 451 | |||
| 452 | function updateUndeclaredConnection | ||
| 453 | input Connection conn; | ||
| 454 | input output list<Connection> conns; | ||
| 455 | algorithm | ||
| 456 | conns := conn :: conns; | ||
| 457 | end updateUndeclaredConnection; | ||
| 458 | |||
| 459 | function updateExpandableConnection | ||
| 460 | input Connection conn; | ||
| 461 | input output list<Connection> conns; | ||
| 462 | protected | ||
| 463 | Connector c1, c2; | ||
| 464 | Type ty1, ty2; | ||
| 465 | MatchKind mk; | ||
| 466 | Expression e1, e2; | ||
| 467 | algorithm | ||
| 468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | Connection.CONNECTION(lhs = c1, rhs = c2) := conn; |
| 469 | 10 | (c1, ty1) := updateExpandableConnector(c1); | |
| 470 | 10 | (c2, ty2) := updateExpandableConnector(c2); | |
| 471 | |||
| 472 | // Check that the types match now that the connectors have been augmented. | ||
| 473 | 10 | e1 := Expression.CREF(ty1, Connector.name(c1)); | |
| 474 | 10 | e2 := Expression.CREF(ty2, Connector.name(c2)); | |
| 475 | 10 | (_, _, _, mk) := TypeCheck.matchExpressions(e1, ty1, e2, ty2, NFTypeCheck.ALLOW_UNKNOWN); | |
| 476 | |||
| 477 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if TypeCheck.isIncompatibleMatch(mk) then |
| 478 | ✗ | Error.addSourceMessageAndFail(Error.CONNECT_TYPE_MISMATCH, | |
| 479 | {Expression.toString(e1), Expression.toString(e2)}, Connector.getInfo(c1)); | ||
| 480 | end if; | ||
| 481 | |||
| 482 | 10 | conns := Connection.CONNECTION(c1, c2) :: conns; | |
| 483 | end updateExpandableConnection; | ||
| 484 | |||
| 485 | function updateExpandableConnector | ||
| 486 | input output Connector conn; | ||
| 487 | output Type ty; | ||
| 488 | protected | ||
| 489 | ComponentRef name; | ||
| 490 | algorithm | ||
| 491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | Connector.CONNECTOR(name = name, ty = ty) := conn; |
| 492 | 20 | name := ComponentRef.updateNodeType(name); | |
| 493 | 20 | ty := Type.setArrayElementType(ty, Type.arrayElementType(ComponentRef.nodeType(name))); | |
| 494 | 20 | conn := Connector.CONNECTOR(name, ty, conn.face, conn.cty, conn.source); | |
| 495 | end updateExpandableConnector; | ||
| 496 | |||
| 497 | function updatePotentiallyPresentVariable | ||
| 498 | input output Variable var; | ||
| 499 | algorithm | ||
| 500 |
2/2✓ Branch 1 taken 1031 times.
✓ Branch 2 taken 183 times.
|
1214 | if ConnectorType.isPotentiallyPresent(var.attributes.connectorType) then |
| 501 | 183 | var.attributes := Component.getAttributes(InstNode.component(ComponentRef.node(var.name))); | |
| 502 | end if; | ||
| 503 | end updatePotentiallyPresentVariable; | ||
| 504 | |||
| 505 | function hashConnector | ||
| 506 | input Connector conn; | ||
| 507 | output Integer res; | ||
| 508 | algorithm | ||
| 509 | 110 | res := stringHashDjb2(ComponentRef.firstName(conn.name)); | |
| 510 | end hashConnector; | ||
| 511 | |||
| 512 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 513 | end NFExpandableConnectors; | ||
| 514 |