Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 94.0% 47 / 0 / 50
Functions: -% 0 / 1 / 1
Branches: 82.1% 23 / 0 / 28

OMCompiler/Compiler/NFFrontEnd/NFConnector.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 uniontype NFConnector
37 import ComponentRef = NFComponentRef;
38 import Expression = NFExpression;
39 import Type = NFType;
40
41 import NFPrefixes.ConnectorType;
42 import NFPrefixes.Variability;
43 import DAE;
44 import Subscript = NFSubscript;
45
46 protected
47 import Origin = NFComponentRef.Origin;
48 import Connector = NFConnector;
49 import NFInstNode.InstNode;
50 import NFInstNode;
51 import ElementSource;
52 import Component = NFComponent;
53 import NFClassTree.ClassTree;
54 import Class = NFClass;
55 import Restriction = NFRestriction;
56 import ComplexType = NFComplexType;
57 import Dimension = NFDimension;
58 import MetaModelica.Dangerous.arrayGetNoBoundsChecking;
59 import MetaModelica.Dangerous.listReverseInPlace;
60
61 public
62 type Face = enumeration(INSIDE, OUTSIDE);
63
64 record CONNECTOR
65 ComponentRef name;
66 Type ty;
67 Face face;
68 ConnectorType.Type cty;
69 DAE.ElementSource source;
70 end CONNECTOR;
71
72 function fromCref
73 input ComponentRef cref;
74 input Type ty;
75 input DAE.ElementSource source;
76 output Connector conn = fromFacedCref(cref, ty, crefFace(cref), source);
77 end fromCref;
78
79 function fromFacedCref
80 input ComponentRef cref;
81 input Type ty;
82 input Face face;
83 input DAE.ElementSource source;
84 output Connector conn;
85 protected
86 InstNode node = ComponentRef.node(cref);
87 Component comp;
88 ConnectorType.Type cty;
89 Restriction res;
90 algorithm
91
2/2
✓ Branch 1 taken 47029 times.
✓ Branch 2 taken 60 times.
47089 if InstNode.isComponent(node) then
92 47029 comp := InstNode.component(node);
93 47029 res := Class.restriction(InstNode.getClass(Component.classInstance(comp)));
94 47029 cty := Component.connectorType(comp);
95 else
96 cty := intBitOr(ConnectorType.UNDECLARED, ConnectorType.POTENTIAL);
97 end if;
98
99 47089 conn := CONNECTOR(ComponentRef.simplifySubscripts(cref), ty, face, cty, source);
100 end fromFacedCref;
101
102 function fromExp
103 "Constructs a list of Connectors from a cref or an array of crefs."
104 input Expression exp;
105 input DAE.ElementSource source;
106 input output list<Connector> conns = {};
107 algorithm
108 conns := match exp
109 26552 case Expression.CREF() then fromCref(exp.cref, exp.ty, source) :: conns;
110
111 case Expression.ARRAY()
112 algorithm
113
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1620 times.
✓ Branch 2 taken 1620 times.
✗ Branch 3 not taken.
3240 for i in arrayLength(exp.elements):-1:1 loop
114 5044 conns := fromExp(arrayGetNoBoundsChecking(exp.elements, i), source, conns);
115 end for;
116 then
117 conns;
118
119 else
120 algorithm
121 ✗ Error.terminate(getInstanceName() + " got unknown expression " +
122 Expression.toString(exp), sourceInfo());
123 ✗ then
124 fail();
125 end match;
126 end fromExp;
127
128 function getType
129 input Connector conn;
130 output Type ty = conn.ty;
131 end getType;
132
133 function getInfo
134 input Connector conn;
135 output SourceInfo info = conn.source.info;
136 end getInfo;
137
138 function variability
139 input Connector conn;
140 output Variability var =
141 Component.variability(InstNode.component(ComponentRef.node(conn.name)));
142 end variability;
143
144 function isEqual
145 input Connector conn1;
146 input Connector conn2;
147 output Boolean isEqual = ComponentRef.isEqual(conn1.name, conn2.name) and
148 conn1.face == conn2.face;
149 end isEqual;
150
151 function isEqualNoSubs
152 input Connector conn1;
153 input Connector conn2;
154 output Boolean isEqual = ComponentRef.isEqualStrip(conn1.name, conn2.name) and
155 conn1.face == conn2.face;
156 end isEqualNoSubs;
157
158 function isPrefix
159 input Connector conn1;
160 input Connector conn2;
161 output Boolean isPrefix = ComponentRef.isPrefix(conn1.name, conn2.name);
162 end isPrefix;
163
164 function isNodeNameEqual
165 input Connector conn1;
166 input Connector conn2;
167 output Boolean isEqual = ComponentRef.nodeName(conn1.name) ==
168 ComponentRef.nodeName(conn2.name);
169 end isNodeNameEqual;
170
171 function isOutside
172 input Connector conn;
173 output Boolean isOutside;
174 protected
175 Face f = conn.face; // Needed due to #4502
176 algorithm
177 2415 isOutside := f == Face.OUTSIDE;
178 end isOutside;
179
180 function isInside
181 input Connector conn;
182 output Boolean isInside;
183 protected
184 Face f = conn.face; // Needed due to #4502
185 algorithm
186 17 isInside := f == Face.INSIDE;
187 end isInside;
188
189 function setOutside
190 input output Connector conn;
191 algorithm
192
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 16 times.
198 if conn.face <> Face.OUTSIDE then
193 16 conn.face := Face.OUTSIDE;
194 end if;
195 end setOutside;
196
197 function isDeleted
198 input Connector conn;
199 output Boolean isDeleted = ComponentRef.isDeleted(conn.name);
200 end isDeleted;
201
202 function isExpandable
203 input Connector conn;
204 output Boolean isExpandable = ConnectorType.isExpandable(conn.cty);
205 end isExpandable;
206
207 function isArray
208 input Connector conn;
209 output Boolean isArray = Type.isArray(conn.ty);
210 end isArray;
211
212 function name
213 input Connector conn;
214 output ComponentRef name = conn.name;
215 end name;
216
217 function toString
218 input Connector conn;
219 output String str = ComponentRef.toString(conn.name);
220 end toString;
221
222 function faceString
223 input Connector conn;
224 output String str = if conn.face == Face.INSIDE then "inside" else "outside";
225 end faceString;
226
227 function hash
228 input Connector conn;
229 output Integer hash = ComponentRef.hash(conn.name);
230 end hash;
231
232 function hashNoSubs
233 input Connector conn;
234 output Integer hash;
235 algorithm
236 2272 hash := ComponentRef.hashStrip(conn.name);
237 end hashNoSubs;
238
239 function split
240 "Splits a connector into its primitive components, while keeping arrays as
241 they are.
242 split(c) => {c.e, c.f, c.s}"
243 input Connector conn;
244 output list<Connector> connl;
245 algorithm
246 52804 connl := splitImpl(conn.name, conn.ty, conn.face, conn.source, conn.cty);
247 52804 connl := listReverseInPlace(connl);
248 end split;
249
250 function scalarize
251 "Splits a connector into scalar elements.
252 scalarize(a/*Real[2]*/.b/*Real[2]*/) => {a[1].b[1], a[1].b[2], a[2].b[1], a[2].b[2]}"
253 input Connector conn;
254 output list<Connector> connl = {};
255 protected
256 ComponentRef name;
257 Type ty;
258 Face face;
259 DAE.ElementSource source;
260 ConnectorType.Type cty;
261 list<ComponentRef> names;
262 algorithm
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40702 times.
40702 CONNECTOR(name, ty, face, cty, source) := conn;
264 40702 names := ComponentRef.scalarizeAll(name, false);
265 40702 ty := Type.arrayElementType(ty);
266
267
2/2
✓ Branch 1 taken 116242 times.
✓ Branch 2 taken 40702 times.
156944 for n in names loop
268 116242 connl := CONNECTOR(n, ty, face, cty, source) :: connl;
269 end for;
270 end scalarize;
271
272 function scalarizePrefix
273 "Splits the prefix of a connector into scalar elements.
274 scalarizePrefix(a/*Real[2]*/.b/*Real[2]*/) => {a[1].b, a[2].b}"
275 input Connector conn;
276 output list<Connector> connl = {};
277 protected
278 ComponentRef name, prefix;
279 Type ty;
280 Face face;
281 DAE.ElementSource source;
282 ConnectorType.Type cty;
283 list<ComponentRef> prefixes;
284 algorithm
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22994 times.
22994 CONNECTOR(name, ty, face, cty, source) := conn;
286 22994 prefix := ComponentRef.rest(name);
287
288
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22994 times.
22994 if ComponentRef.isEmpty(prefix) then
289 connl := {conn};
290 ✗ return;
291 end if;
292
293 22994 prefixes := ComponentRef.scalarizeAll(prefix, false);
294 22994 ty := ComponentRef.getSubscriptedType(ComponentRef.first(name));
295
296
2/2
✓ Branch 0 taken 23610 times.
✓ Branch 1 taken 22994 times.
46604 for p in prefixes loop
297 23610 name := ComponentRef.prepend(p, name);
298 23610 connl := CONNECTOR(name, ty, face, cty, source) :: connl;
299 end for;
300
301 22994 connl := listReverseInPlace(connl);
302 end scalarizePrefix;
303
304 function addSubscripts
305 input list<Subscript> subscripts;
306 input output Connector conn;
307 algorithm
308 62 conn.name := ComponentRef.mergeSubscripts(subscripts, conn.name, true);
309 conn.ty := Type.subscript(conn.ty, subscripts);
310 end addSubscripts;
311
312 protected
313 function crefFace
314 "Determines whether a cref refers to an inside or outside connector, where
315 an outside connector is a connector where the first part of the cref is a
316 connector, and an inside connector all other crefs."
317 input ComponentRef cref;
318 output Face face;
319 algorithm
320 face := match cref
321 // Simple identifiers must be connectors and thus outside.
322 case ComponentRef.CREF(restCref = ComponentRef.EMPTY()) then Face.OUTSIDE;
323 // Otherwise, check first part of the cref.
324
2/2
✓ Branch 3 taken 19790 times.
✓ Branch 4 taken 7892 times.
27682 else if InstNode.isConnector(ComponentRef.node(ComponentRef.firstNonScope(cref)))
325 then Face.OUTSIDE else Face.INSIDE;
326 end match;
327 end crefFace;
328
329 function splitImpl
330 input ComponentRef name;
331 input Type ty;
332 input Face face;
333 input DAE.ElementSource source;
334 input ConnectorType.Type cty;
335 input list<Dimension> dims = {};
336 input output list<Connector> conns = {};
337 protected
338 ComplexType ct;
339 ClassTree tree;
340 algorithm
341 conns := match ty
342 // A connector, split into connector elements.
343 case Type.COMPLEX(complexTy = ct as ComplexType.CONNECTOR())
344 algorithm
345 26426 conns := splitImpl2(name, face, source, ct.potentials, dims, conns);
346 26426 conns := splitImpl2(name, face, source, ct.flows, dims, conns);
347 26426 conns := splitImpl2(name, face, source, ct.streams, dims, conns);
348 then
349 conns;
350
351 // An external object, don't split.
352 case Type.COMPLEX(complexTy = ComplexType.EXTERNAL_OBJECT())
353 16 then CONNECTOR(name, Type.liftArrayLeftList(ty, dims), face, cty, source) :: conns;
354
355 // A record, split into record elements.
356 case Type.COMPLEX()
357 algorithm
358 10392 tree := Class.classTree(InstNode.getClass(Type.complexNode(ty)));
359
4/4
✓ Branch 1 taken 20718 times.
✓ Branch 2 taken 10392 times.
✓ Branch 4 taken 20718 times.
✓ Branch 5 taken 10392 times.
62220 conns := splitImpl2(name, face, source,
360 list(InstNode.scopeRef(c) for c in ClassTree.getComponents(tree)), dims, conns);
361 then
362 conns;
363
364 // An array, split according to the element type.
365 case Type.ARRAY()
366 45245 then splitImpl(name, ty.elementType, face, source, cty, listAppend(dims, ty.dimensions), conns);
367
368 110642 else CONNECTOR(name, Type.liftArrayLeftList(ty, dims), face, cty, source) :: conns;
369 end match;
370 end splitImpl;
371
372 function splitImpl2
373 input ComponentRef name;
374 input Face face;
375 input DAE.ElementSource source;
376 input list<NFInstNode.ScopeRef> comps;
377 input list<Dimension> dims;
378 input output list<Connector> conns;
379 protected
380 Component c;
381 ComponentRef cref;
382 Type ty;
383 ConnectorType.Type cty;
384 InstNode comp;
385 algorithm
386
2/2
✓ Branch 0 taken 94783 times.
✓ Branch 1 taken 89670 times.
184453 for comp_ref in comps loop
387 94783 comp := InstNode.borrow(comp_ref);
388 94783 c := InstNode.component(comp);
389 94783 ty := Component.getType(c);
390 94783 cty := Component.connectorType(c);
391
392
2/2
✓ Branch 1 taken 94672 times.
✓ Branch 2 taken 111 times.
94783 if not ConnectorType.isPotentiallyPresent(cty) then
393 94672 cref := ComponentRef.append(ComponentRef.fromNode(comp, ty), name);
394 94672 conns := splitImpl(cref, ty, face, source, cty, dims, conns);
395 end if;
396 end for;
397 end splitImpl2;
398
399 annotation(__OpenModelica_Interface="nf_frontend");
400 end NFConnector;
401