Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.1% 750 / 0 / 851
Functions: -% 0 / 1 / 1
Branches: 84.3% 555 / 0 / 658

OMCompiler/Compiler/NFFrontEnd/NFFlatten.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 NFFlatten
37 " file: NFFlatten.mo
38 package: NFFlatten
39 description: Flattening
40
41
42 New instantiation, enable with -d=newInst.
43 "
44
45 import Binding = NFBinding;
46 import Equation = NFEquation;
47 import NFFunction.Function;
48 import NFInstNode.InstNode;
49 import NFInstNode;
50 import Statement = NFStatement;
51 import FlatModel = NFFlatModel;
52 import Algorithm = NFAlgorithm;
53 import CardinalityTable = NFCardinalityTable;
54
55 protected
56 import Absyn;
57 import Attributes = NFAttributes;
58 import ComponentRef = NFComponentRef;
59 import Dimension = NFDimension;
60 import ExecStat.execStat;
61 import ExpressionIterator = NFExpressionIterator;
62 import Expression = NFExpression;
63 import Flags;
64 import List;
65 import Call = NFCall;
66 import Class = NFClass;
67 import NFClassTree.ClassTree;
68 import Component = NFComponent;
69 import NFModifier.Modifier;
70 import Sections = NFSections;
71 import NFOCConnectionGraph;
72 import Prefixes = NFPrefixes;
73 import RangeIterator = NFRangeIterator;
74 import StringUtil;
75 import Subscript = NFSubscript;
76 import Type = NFType;
77 import Util;
78 import MetaModelica.Dangerous.listReverseInPlace;
79 import ConnectionSets = NFConnectionSets.ConnectionSets;
80 import Connection = NFConnection;
81 import Connector = NFConnector;
82 import ConnectEquations = NFConnectEquations;
83 import Connections = NFConnections;
84 import Face = NFConnector.Face;
85 import System;
86 import ComplexType = NFComplexType;
87 import NFInstNode.CachedData;
88 import NFPrefixes.{ConnectorType, Direction, Variability, Visibility, Purity, Parallelism};
89 import Variable = NFVariable;
90 import ElementSource;
91 import Ceval = NFCeval;
92 import SimplifyExp = NFSimplifyExp;
93 import Restriction = NFRestriction;
94 import EvalConstants = NFEvalConstants;
95 import SimplifyModel = NFSimplifyModel;
96 import InstNodeType = NFInstNode.InstNodeType;
97 import ExpandableConnectors = NFExpandableConnectors;
98 import SCode;
99 import SCodeUtil;
100 import DAE;
101 import Structural = NFStructural;
102 import ArrayConnections = NFArrayConnections;
103 import ResizableConnections = NFResizableConnections;
104 import UnorderedMap;
105 import UnorderedSet;
106 import Inline = NFInline;
107 import ExpandExp = NFExpandExp;
108 import InstUtil = NFInstUtil;
109 import StreamFlowAlias = NFStreamFlowAlias;
110
111 public
112 type FunctionTree = FunctionTreeImpl.Tree;
113 type DeletedVariables = UnorderedSet<ComponentRef>;
114
115 encapsulated package FunctionTreeImpl
116 import Absyn.Path;
117 import NFFunction.Function;
118 import BaseAvlTree;
119
120 extends BaseAvlTree;
121 redeclare type Key = Absyn.Path;
122 redeclare type Value = Function;
123
124 redeclare function extends keyStr
125 algorithm
126 ✗ outString := AbsynUtil.pathString(inKey);
127 end keyStr;
128
129 redeclare function extends valueStr
130 algorithm
131 outString := "";
132 end valueStr;
133
134 redeclare function extends keyCompare
135 algorithm
136 60247 outResult := AbsynUtil.pathCompareNoQual(inKey1, inKey2);
137 end keyCompare;
138
139 redeclare function addConflictDefault = addConflictKeep;
140 end FunctionTreeImpl;
141
142 uniontype FlattenSettings
143 record SETTINGS
144 Boolean scalarize;
145 Boolean arrayConnect;
146 Boolean nfAPI;
147 Boolean relaxedErrorChecking;
148 Boolean newBackend;
149 Boolean vectorizeBindings;
150 Boolean implicitStartAttribute;
151 Boolean minimalEval;
152 end SETTINGS;
153 end FlattenSettings;
154
155 uniontype Prefix
156 record PREFIX
157 InstNode root;
158 ComponentRef prefix;
159 end PREFIX;
160
161 record INDEXED_PREFIX
162 InstNode root;
163 ComponentRef prefix;
164 ComponentRef indexedPrefix;
165 end INDEXED_PREFIX;
166
167 function new
168 input InstNode root;
169 input Boolean indexed = false;
170 output Prefix prefix;
171 algorithm
172
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 1390 times.
1595 prefix := if indexed then
173 INDEXED_PREFIX(root, ComponentRef.EMPTY(), ComponentRef.EMPTY()) else
174 PREFIX(root, ComponentRef.EMPTY());
175 end new;
176
177 function isEmpty
178 input Prefix prefix;
179 output Boolean empty;
180 algorithm
181 empty := match prefix
182 16712 case PREFIX() then ComponentRef.isEmpty(prefix.prefix);
183 ✗ case INDEXED_PREFIX() then ComponentRef.isEmpty(prefix.indexedPrefix);
184 end match;
185 end isEmpty;
186
187 function isIndexed
188 input Prefix prefix;
189 output Boolean indexed;
190 algorithm
191 indexed := match prefix
192 case INDEXED_PREFIX() then true;
193 else false;
194 end match;
195 end isIndexed;
196
197 function push
198 input InstNode node;
199 input Type ty;
200 input list<Dimension> dims;
201 input output Prefix prefix;
202 algorithm
203 () := match prefix
204 case PREFIX()
205 algorithm
206 270557 prefix.prefix := ComponentRef.prefixCref(node, ty, {}, prefix.prefix);
207 then
208 ();
209
210 case INDEXED_PREFIX()
211 algorithm
212 8441 prefix.prefix := ComponentRef.prefixCref(node, ty, {}, prefix.prefix);
213 8441 prefix.indexedPrefix := ComponentRef.prefixCref(node, ty, {}, prefix.indexedPrefix);
214 8441 prefix.indexedPrefix := ComponentRef.setSubscripts(makeBindingIterators(prefix.indexedPrefix, dims),
215 prefix.indexedPrefix);
216 then
217 ();
218 end match;
219 end push;
220
221 function pop
222 input output Prefix prefix;
223 algorithm
224 () := match prefix
225 case PREFIX()
226 algorithm
227 5427 prefix.prefix := ComponentRef.rest(prefix.prefix);
228 then
229 ();
230
231 case INDEXED_PREFIX()
232 algorithm
233 56 prefix.prefix := ComponentRef.rest(prefix.prefix);
234 56 prefix.indexedPrefix := ComponentRef.rest(prefix.indexedPrefix);
235 then
236 ();
237 end match;
238 end pop;
239
240 function prefix
241 input Prefix prefix;
242 output ComponentRef cref;
243 algorithm
244 cref := match prefix
245 261396 case PREFIX() then prefix.prefix;
246 8158 case INDEXED_PREFIX() then prefix.prefix;
247 end match;
248 end prefix;
249
250 function indexedPrefix
251 input Prefix prefix;
252 output ComponentRef cref;
253 algorithm
254 cref := match prefix
255 495906 case PREFIX() then prefix.prefix;
256 22492 case INDEXED_PREFIX() then prefix.indexedPrefix;
257 end match;
258 end indexedPrefix;
259
260 function toNonIndexedPrefix
261 input output Prefix prefix;
262 algorithm
263 prefix := match prefix
264 case PREFIX() then prefix;
265 1656 case INDEXED_PREFIX() then PREFIX(prefix.root, prefix.prefix);
266 end match;
267 end toNonIndexedPrefix;
268
269 function apply
270 input Prefix prefix;
271 input output ComponentRef cref;
272 algorithm
273 422705 cref := ComponentRef.transferSubscripts(indexedPrefix(prefix), cref);
274 end apply;
275
276 function subscript
277 input list<Subscript> subs;
278 input output Prefix prefix;
279 algorithm
280 () := match prefix
281 case PREFIX()
282 algorithm
283 6176 prefix.prefix := ComponentRef.setSubscripts(subs, prefix.prefix);
284 then
285 ();
286
287 case INDEXED_PREFIX()
288 algorithm
289 ✗ prefix.prefix := ComponentRef.setSubscripts(subs, prefix.prefix);
290 then
291 ();
292 end match;
293 end subscript;
294
295 function toString
296 input Prefix pre;
297 output String str = ComponentRef.toString(prefix(pre));
298 end toString;
299
300 function rootNode
301 input Prefix pre;
302 output InstNode node;
303 algorithm
304 node := match pre
305 58 case PREFIX() then pre.root;
306 ✗ case INDEXED_PREFIX() then pre.root;
307 end match;
308 end rootNode;
309
310 function instanceName
311 input Prefix pre;
312 output String str;
313 algorithm
314 58 str := InstNode.name(rootNode(pre));
315
316
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 54 times.
58 if not ComponentRef.isEmpty(indexedPrefix(pre)) then
317 54 str := str + "." + toString(pre);
318 end if;
319 end instanceName;
320 end Prefix;
321
322 constant Prefix EMPTY_PREFIX = Prefix.PREFIX(InstNode.EMPTY_NODE(), ComponentRef.EMPTY());
323 constant Prefix EMPTY_INDEXED_PREFIX = Prefix.INDEXED_PREFIX(InstNode.EMPTY_NODE(), ComponentRef.EMPTY(), ComponentRef.EMPTY());
324
325 function flatten
326 input InstNode classInst;
327 input Absyn.Path classPath;
328 input Boolean getConnectionResolved = true;
329 output FlatModel flatModel;
330 protected
331 Sections sections;
332 list<Variable> vars;
333 list<Equation> eql, ieql;
334 list<Algorithm> alg, ialg;
335 DAE.ElementSource src;
336 FlattenSettings settings;
337 DeletedVariables deleted_vars;
338 Prefix prefix;
339 algorithm
340
20/22
✓ Branch 1 taken 1595 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1595 times.
✓ Branch 8 taken 1594 times.
✓ Branch 9 taken 1 time.
✓ Branch 11 taken 1390 times.
✓ Branch 12 taken 205 times.
✓ Branch 14 taken 1392 times.
✓ Branch 15 taken 203 times.
✓ Branch 17 taken 1454 times.
✓ Branch 18 taken 141 times.
✓ Branch 20 taken 1386 times.
✓ Branch 21 taken 68 times.
✓ Branch 23 taken 1454 times.
✓ Branch 24 taken 141 times.
✓ Branch 26 taken 1592 times.
✓ Branch 27 taken 3 times.
✓ Branch 29 taken 1580 times.
✓ Branch 30 taken 12 times.
✓ Branch 32 taken 219 times.
✓ Branch 33 taken 1376 times.
10610 settings := FlattenSettings.SETTINGS(
341 Flags.isSet(Flags.NF_SCALARIZE),
342 // connections in for equations over resizable parameters can only be resolved with the array handler
343 Flags.isSet(Flags.ARRAY_CONNECT) or Flags.getConfigBool(Flags.RESIZABLE_ARRAYS),
344 Flags.isSet(Flags.NF_API),
345 Flags.isSet(Flags.NF_API) or Flags.getConfigBool(Flags.CHECK_MODEL),
346 Flags.getConfigBool(Flags.NEW_BACKEND),
347 Flags.isSet(Flags.VECTORIZE_BINDINGS),
348 Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "implicitParameterStartAttribute"),
349 Flags.getConfigString(Flags.EVALUATE_STRUCTURAL_PARAMETERS) <> "all"
350 );
351
352 1595 prefix := Prefix.new(classInst, indexed = settings.vectorizeBindings);
353
354 1595 sections := Sections.EMPTY();
355 1595 src := ElementSource.createElementSource(InstNode.info(classInst));
356 1595 src := ElementSource.addCommentToSource(src,
357 SCodeUtil.getElementComment(InstNode.definition(classInst)));
358
359 // the array connection handlers check connectors with subscripts against the deleted components
360
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1580 times.
1595 if settings.arrayConnect then
361 15 deleted_vars := UnorderedSet.new(ComponentRef.hashStrip, ComponentRef.isEqualStrip);
362 else
363 1580 deleted_vars := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
364 end if;
365
366 1595 (vars, sections) := flattenClass(InstNode.getClass(classInst), prefix,
367 Visibility.PUBLIC, NONE(), {}, sections, deleted_vars, settings);
368 1588 vars := listReverseInPlace(vars);
369
370 flatModel := match sections
371 case Sections.SECTIONS()
372 algorithm
373 1080 eql := listReverseInPlace(sections.equations);
374 1080 ieql := listReverseInPlace(sections.initialEquations);
375 1080 alg := listReverseInPlace(sections.algorithms);
376 1080 ialg := listReverseInPlace(sections.initialAlgorithms);
377 1080 then
378 FlatModel.FLAT_MODEL(classPath, vars, eql, ieql, alg, ialg, src);
379
380 508 else FlatModel.FLAT_MODEL(classPath, vars, {}, {}, {}, {}, src);
381 end match;
382
383 // get inputs and outputs for algorithms now that types are computed
384
8/8
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 1588 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 1588 times.
✓ Branch 5 taken 52 times.
✓ Branch 6 taken 1588 times.
✓ Branch 7 taken 52 times.
✓ Branch 8 taken 1588 times.
1786 flatModel.algorithms := list(Algorithm.setInputsOutputs(al) for al in flatModel.algorithms);
385 flatModel.initialAlgorithms := list(Algorithm.setInputsOutputs(al) for al in flatModel.initialAlgorithms);
386
387 1588 execStat(getInstanceName());
388 1588 InstUtil.dumpFlatModelDebug("flatten", flatModel);
389
390
2/2
✓ Branch 0 taken 1586 times.
✓ Branch 1 taken 2 times.
1588 if getConnectionResolved then
391
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 1383 times.
1586 if settings.newBackend then
392 203 flatModel.equations := evaluateIfWithConnects(flatModel.equations);
393 end if;
394
395
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1571 times.
1586 if settings.arrayConnect then
396 15 flatModel := resolveArrayConnections(flatModel, deleted_vars);
397 else
398 1571 flatModel := resolveConnections(flatModel, deleted_vars, settings);
399 end if;
400 1585 InstUtil.dumpFlatModelDebug("connections", flatModel);
401 end if;
402
403
4/4
✓ Branch 0 taken 240737 times.
✓ Branch 1 taken 1587 times.
✓ Branch 2 taken 240737 times.
✓ Branch 3 taken 1587 times.
243911 flatModel.variables := list(updateVariability(var) for var in flatModel.variables);
404
405
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1587 times.
1587 if not Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "illegalConditionalContext") then
406 1587 checkDeletedVarRefs(flatModel, deleted_vars, settings);
407 end if;
408 end flatten;
409
410 function flattenConnection
411 input InstNode classInst;
412 input Absyn.Path classPath;
413 output Connections conns;
414 protected
415 FlatModel flatModel;
416 DeletedVariables deleted_vars;
417 algorithm
418 2 flatModel := flatten(classInst, classPath, false);
419 2 deleted_vars := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
420
421 // get the connections from the model
422 2 (flatModel, conns) := Connections.collectConnections(flatModel, function isDeletedCref(deletedVars = deleted_vars));
423 // Elaborate expandable connectors.
424 2 (_, conns) := ExpandableConnectors.elaborate(flatModel, conns);
425 2 conns := Connections.collectFlows(flatModel, conns);
426 end flattenConnection;
427
428 function collectFunctions
429 input FlatModel flatModel;
430 output FunctionTree funcs;
431 algorithm
432 1574 funcs := FunctionTree.new();
433 1574 funcs := List.fold(flatModel.variables, collectComponentFuncs, funcs);
434 1574 funcs := List.fold(flatModel.equations, collectEquationFuncs, funcs);
435 1574 funcs := List.fold(flatModel.initialEquations, collectEquationFuncs, funcs);
436 1574 funcs := List.fold(flatModel.algorithms, collectAlgorithmFuncs, funcs);
437 1574 funcs := List.fold(flatModel.initialAlgorithms, collectAlgorithmFuncs, funcs);
438 1574 execStat(getInstanceName());
439 end collectFunctions;
440
441 function fillVectorizedVariableBinding
442 input output Variable var;
443 protected
444 list<tuple<String, Binding>> ty_attrs = {};
445 String attr_name;
446 Binding attr_binding;
447 algorithm
448 6556 var.binding := fillVectorizedBinding(var.binding, var.ty);
449
450
2/2
✓ Branch 0 taken 13396 times.
✓ Branch 1 taken 6556 times.
19952 for ty_attr in var.typeAttributes loop
451 13396 (attr_name, attr_binding) := ty_attr;
452 13396 attr_binding := fillVectorizedBinding(attr_binding,
453 Type.copyDims(var.ty, Binding.getType(attr_binding)));
454 13396 ty_attrs := (attr_name, attr_binding) :: ty_attrs;
455 end for;
456
457 6556 var.typeAttributes := listReverseInPlace(ty_attrs);
458 end fillVectorizedVariableBinding;
459
460 protected
461 function flattenClass
462 input Class cls;
463 input Prefix prefix;
464 input Visibility visibility;
465 input Option<Binding> binding;
466 input output list<Variable> vars;
467 input output Sections sections;
468 input DeletedVariables deletedVars;
469 input FlattenSettings settings;
470 protected
471 array<InstNode> comps;
472 list<Binding> bindings = {};
473 Binding b;
474 algorithm
475 () := match cls
476 case Class.INSTANCED_CLASS(restriction = Restriction.TYPE()) then ();
477
478 case Class.INSTANCED_CLASS(elements = ClassTree.FLAT_TREE(components = comps))
479 algorithm
480
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 43527 times.
✓ Branch 2 taken 6199 times.
✓ Branch 3 taken 37328 times.
43527 if isSome(binding) then
481 6199 SOME(b) := binding;
482
483
2/2
✓ Branch 1 taken 5483 times.
✓ Branch 2 taken 716 times.
6199 if Binding.isBound(b) then
484 5483 b := flattenBinding(b, Prefix.pop(prefix));
485 5483 bindings := getRecordBindings(b, comps, prefix);
486 end if;
487 end if;
488
489
2/2
✓ Branch 0 taken 38044 times.
✓ Branch 1 taken 5483 times.
43527 if listEmpty(bindings) then
490
2/2
✓ Branch 1 taken 226619 times.
✓ Branch 2 taken 38038 times.
264657 for c in comps loop
491 226619 (vars, sections) := flattenComponent(c, prefix, visibility, binding, vars, sections, deletedVars, settings);
492 end for;
493 else
494
2/2
✓ Branch 1 taken 56718 times.
✓ Branch 2 taken 5483 times.
62201 for c in comps loop
495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56718 times.
56718 b :: bindings := bindings;
496 56718 (vars, sections) := flattenComponent(c, prefix, visibility, SOME(b), vars, sections, deletedVars, settings);
497 end for;
498 end if;
499
500 43521 sections := flattenSections(cls.sections, Prefix.toNonIndexedPrefix(prefix), sections, settings);
501 then
502 ();
503
504 case Class.TYPED_DERIVED()
505 algorithm
506 3 (vars, sections) :=
507 flattenClass(InstNode.getClass(cls.baseClass), prefix, visibility, binding, vars, sections, deletedVars, settings);
508 then
509 ();
510
511 case Class.INSTANCED_BUILTIN() then ();
512
513 else
514 algorithm
515 ✗ Error.terminate(getInstanceName() + " got non-instantiated component " + Prefix.toString(prefix) + "\n", sourceInfo());
516 then
517 ();
518
519 end match;
520 end flattenClass;
521
522 function flattenComponent
523 input InstNode component;
524 input Prefix prefix;
525 input Visibility visibility;
526 input Option<Binding> outerBinding;
527 input output list<Variable> vars;
528 input output Sections sections;
529 input DeletedVariables deletedVars;
530 input FlattenSettings settings;
531 protected
532 InstNode comp_node;
533 Component c;
534 Type ty;
535 Binding condition;
536 Class cls;
537 Visibility vis;
538 list<Variable> children;
539 algorithm
540 // Remove components that are only outer.
541
4/4
✓ Branch 1 taken 283332 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 1528 times.
✓ Branch 5 taken 281804 times.
283337 if InstNode.isEmpty(component) or InstNode.isOnlyOuter(component) then
542 1533 return;
543 end if;
544
545 281804 comp_node := InstNode.resolveOuter(component);
546 281804 c := InstNode.component(comp_node);
547
548 () := match c
549 case Component.COMPONENT(condition = condition, ty = ty)
550 algorithm
551 // Delete the component if it has a condition that's false.
552
2/2
✓ Branch 1 taken 2992 times.
✓ Branch 2 taken 278812 times.
281804 if isDeletedComponent(condition, prefix) then
553 2992 deleteComponent(component, prefix, deletedVars);
554 2992 return;
555 end if;
556
557 278812 cls := InstNode.getClass(c.classInst);
558
2/2
✓ Branch 1 taken 12502 times.
✓ Branch 2 taken 266310 times.
278812 vis := if InstNode.isProtected(component) then Visibility.PROTECTED else visibility;
559
560 (vars, sections) := match getComponentType(ty, settings)
561 case ComponentType.COMPLEX
562 37576 then flattenComplexComponent(comp_node, c, cls, ty,
563 vis, outerBinding, prefix, vars, sections, deletedVars, settings);
564
565 case ComponentType.NORMAL
566 241046 then flattenSimpleComponent(comp_node, c, vis, outerBinding,
567 Class.getTypeAttributes(cls), prefix, vars, sections, settings, {});
568
569 case ComponentType.RECORD
570 algorithm
571 190 (children, sections) := flattenComplexComponent(comp_node, c, cls, ty,
572 vis, outerBinding, prefix, {}, sections, deletedVars, settings);
573 190 then flattenSimpleComponent(comp_node, c, vis, outerBinding,
574 Class.getTypeAttributes(cls), prefix, vars, sections, settings, listReverse(children));
575
576 else
577 algorithm
578 ✗ Error.terminate(getInstanceName() + " got unknown component", sourceInfo());
579 ✗ then
580 fail();
581 end match;
582 then
583 ();
584
585 // A component that was already deleted during e.g. typing.
586 case _ guard Component.isDeleted(c)
587 algorithm
588 ✗ deleteComponent(component, prefix, deletedVars);
589 then
590 ();
591
592 else
593 algorithm
594 ✗ Error.terminate(getInstanceName() + " got unknown component", sourceInfo());
595 ✗ then
596 fail();
597
598 end match;
599 end flattenComponent;
600
601 function isDeletedComponent
602 input Binding condition;
603 input Prefix prefix;
604 output Boolean isDeleted;
605 protected
606 Expression exp;
607 Binding cond;
608 algorithm
609
2/2
✓ Branch 1 taken 5660 times.
✓ Branch 2 taken 276144 times.
281804 if Binding.isBound(condition) then
610 5660 cond := flattenBinding(condition, prefix);
611 5660 exp := Binding.getTypedExp(cond);
612 5660 exp := Ceval.evalExp(exp, Ceval.EvalTarget.new(Binding.getInfo(cond), NFInstContext.CONDITION));
613 5660 exp := Expression.expandSplitIndices(exp);
614
615 // Hack to make arrays work when all elements have the same value.
616
1/2
✓ Branch 1 taken 5660 times.
✗ Branch 2 not taken.
5660 if Expression.arrayAllEqual(exp) then
617 5660 exp := Expression.arrayFirstScalar(exp);
618 end if;
619
620 isDeleted := match exp
621 5660 case Expression.BOOLEAN() then not exp.value;
622 else
623 algorithm
624 ✗ Error.addSourceMessage(Error.CONDITIONAL_EXP_WITHOUT_VALUE,
625 {Expression.toString(exp)}, Binding.getInfo(cond));
626 ✗ then
627 fail();
628 end match;
629 else
630 isDeleted := false;
631 end if;
632 end isDeletedComponent;
633
634 function deleteComponent
635 input InstNode node;
636 input Prefix prefix;
637 input DeletedVariables deletedVars;
638 protected
639 ComponentRef cref;
640 algorithm
641 2992 cref := ComponentRef.prefixCref(node, Type.UNKNOWN(), {}, Prefix.prefix(prefix));
642 2992 UnorderedSet.add(cref, deletedVars);
643 end deleteComponent;
644
645 function getComponentType
646 input Type ty;
647 input FlattenSettings settings;
648 output ComponentType compTy;
649 algorithm
650 compTy := match ty
651 case Type.COMPLEX(complexTy = ComplexType.EXTERNAL_OBJECT())
652 then ComponentType.NORMAL;
653 case Type.COMPLEX(complexTy = ComplexType.RECORD()) guard(settings.newBackend)
654 then ComponentType.RECORD;
655 case Type.COMPLEX() then ComponentType.COMPLEX;
656 52463 case Type.ARRAY() then getComponentType(ty.elementType, settings);
657 else ComponentType.NORMAL;
658 end match;
659 end getComponentType;
660
661 type ComponentType = enumeration(NORMAL, COMPLEX, RECORD);
662
663 function flattenSimpleComponent
664 input InstNode node;
665 input Component comp;
666 input Visibility visibility;
667 input Option<Binding> outerBinding;
668 input list<Modifier> typeAttrs;
669 input Prefix prefix;
670 input output list<Variable> vars;
671 input output Sections sections;
672 input FlattenSettings settings;
673 input list<Variable> children;
674 protected
675 InstNode comp_node = node;
676 ComponentRef name;
677 Binding binding;
678 Type ty;
679 SCode.Comment cmt;
680 SourceInfo info;
681 Attributes comp_attr;
682 Equation eq;
683 list<tuple<String, Binding>> ty_attrs;
684 Variability var;
685 Boolean unfix;
686 Prefix pre;
687 Variable v;
688 Boolean fillVectorizedBindingFails = false;
689 algorithm
690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241236 times.
241236 Component.COMPONENT(ty = ty, binding = binding, attributes = comp_attr, comment = cmt, info = info) := comp;
691 241236 checkUnspecifiedEnumType(ty, node, info);
692 241235 var := comp_attr.variability;
693
694
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 241235 times.
✓ Branch 2 taken 183099 times.
✓ Branch 3 taken 58136 times.
241235 if isSome(outerBinding) then
695 58136 SOME(binding) := outerBinding;
696
4/4
✓ Branch 1 taken 1451 times.
✓ Branch 2 taken 56685 times.
✓ Branch 3 taken 1333 times.
✓ Branch 4 taken 118 times.
58136 unfix := Binding.isUnbound(binding) and var == Variability.PARAMETER;
697 else
698 183099 binding := flattenBinding(binding, prefix);
699 unfix := false;
700 end if;
701
702 // If the component is vectorized and the binding uses variables of the component,
703 // move the binding into an equation as fillVectorizedBinding is insufficient.
704
10/10
✓ Branch 0 taken 7113 times.
✓ Branch 1 taken 234120 times.
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 6990 times.
✓ Branch 5 taken 52 times.
✓ Branch 6 taken 71 times.
✓ Branch 8 taken 44 times.
✓ Branch 9 taken 8 times.
✓ Branch 13 taken 17 times.
✓ Branch 14 taken 27 times.
241233 if not settings.scalarize and not settings.vectorizeBindings and Binding.isBound(binding)
705 and not Prefix.isEmpty(prefix) and Type.isArray(ComponentRef.nodeType(Prefix.prefix(prefix))) then
706 17 fillVectorizedBindingFails := containsPrefix(Binding.getExp(binding), prefix);
707 end if;
708
709 // If the component is an array component with a binding and at least discrete
710 // variability, and scalarization is enabled, move the binding into an equation.
711 // This avoids having to scalarize the binding.
712
6/6
✓ Branch 0 taken 239921 times.
✓ Branch 1 taken 1312 times.
✓ Branch 2 taken 7113 times.
✓ Branch 3 taken 232808 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 8424 times.
241233 if not settings.nfAPI and settings.scalarize or fillVectorizedBindingFails then
713
9/10
✓ Branch 0 taken 123705 times.
✓ Branch 1 taken 109104 times.
✓ Branch 3 taken 40368 times.
✓ Branch 4 taken 83337 times.
✓ Branch 7 taken 40366 times.
✓ Branch 8 taken 2 times.
✓ Branch 10 taken 22418 times.
✓ Branch 11 taken 17948 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 214861 times.
232809 if var >= Variability.DISCRETE and Type.isArray(ty) and
714 not Type.isExternalObject(Type.arrayElementType(ty)) and Binding.isBound(binding)
715 or fillVectorizedBindingFails then
716 17948 name := ComponentRef.prefixCref(comp_node, ty, {}, Prefix.prefix(prefix));
717 17948 eq := Equation.makeEquality(Expression.CREF(ty, name), Binding.getTypedExp(binding), ty,
718 ElementSource.createElementSource(info), scalarizeMode = NFEquation.ScalarizeMode.DONT_SCALARIZE);
719 17948 sections := Sections.prependEquation(eq, sections);
720 binding := NFBinding.EMPTY_BINDING;
721
722 // Moving the binding of an input variable to an equation can change how
723 // the variable is counted when counting variables and equations, but
724 // since there's no way to override such a binding from outside the model
725 // we can remove the input prefix to keep the balance.
726
4/4
✓ Branch 0 taken 16660 times.
✓ Branch 1 taken 1288 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 16659 times.
17948 if comp_attr.direction == Direction.INPUT and Prefix.isEmpty(prefix) then
727 1 comp_attr.direction := Direction.NONE;
728 2 Error.addSourceMessage(Error.TOP_LEVEL_INPUT_WITH_BINDING,
729 {ComponentRef.toString(name)}, info);
730 end if;
731 end if;
732 end if;
733
734 241233 ty := flattenType(ty, prefix, info);
735 241233 verifyDimensions(Type.arrayDims(ty), comp_node);
736 241232 pre := Prefix.push(comp_node, ty, Type.arrayDims(ty), prefix);
737
4/4
✓ Branch 0 taken 471693 times.
✓ Branch 1 taken 241232 times.
✓ Branch 2 taken 471693 times.
✓ Branch 3 taken 241232 times.
712925 ty_attrs := list(flattenTypeAttribute(m, prefix) for m in typeAttrs);
738
739 // Set fixed = false for parameters that are part of a record instance whose
740 // binding couldn't be split and was moved to an initial equation.
741
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 241114 times.
241232 if unfix then
742 118 ty_attrs := Binding.setAttr(ty_attrs, "fixed",
743 Binding.makeFlat(Expression.BOOLEAN(false), Variability.CONSTANT, NFBinding.Source.GENERATED));
744 end if;
745
746 // kabdelhak: add dummy backend info, will be changed to actual value in
747 // conversion to backend process. NBackendDAE.lower
748 241232 name := Prefix.prefix(pre);
749 241232 v := Variable.VARIABLE(name, ty, binding, visibility, comp_attr, ty_attrs, children, cmt, info, NFBackendExtension.DUMMY_BACKEND_INFO);
750
751
6/6
✓ Branch 0 taken 191593 times.
✓ Branch 1 taken 49639 times.
✓ Branch 2 taken 95764 times.
✓ Branch 3 taken 95829 times.
✓ Branch 6 taken 95683 times.
✓ Branch 7 taken 81 times.
241232 if not settings.relaxedErrorChecking and var < Variability.DISCRETE and
752 not unfix and not Type.isComplex(Type.arrayElementType(ty)) then
753 // Check that the component has a binding if it's required to have one.
754 95683 v := verifyBinding(v, var, binding, settings);
755 end if;
756
757 vars := v :: vars;
758 end flattenSimpleComponent;
759
760 function checkUnspecifiedEnumType
761 input Type ty;
762 input InstNode node;
763 input SourceInfo info;
764 algorithm
765 () := match ty
766 case Type.ENUMERATION(literals = {})
767 algorithm
768 2 Error.addSourceMessage(Error.UNSPECIFIED_ENUM_COMPONENT, {InstNode.name(node)}, info);
769 1 then
770 fail();
771
772 else ();
773 end match;
774 end checkUnspecifiedEnumType;
775
776 function flattenTypeAttribute
777 input Modifier attr;
778 input Prefix prefix;
779 output tuple<String, Binding> outAttr;
780 protected
781 Binding binding;
782 algorithm
783 471693 binding := flattenBinding(Modifier.binding(attr), prefix, isTypeAttribute = true);
784 471693 outAttr := (Modifier.name(attr), binding);
785 end flattenTypeAttribute;
786
787 function isTypeAttributeNamed
788 input String name;
789 input tuple<String, Binding> attr;
790 output Boolean isNamed;
791 protected
792 String attr_name;
793 algorithm
794 ✗ (attr_name, _) := attr;
795 ✗ isNamed := name == attr_name;
796 end isTypeAttributeNamed;
797
798 function verifyBinding
799 input output Variable var;
800 input Variability variability;
801 input Binding binding;
802 input FlattenSettings settings;
803 protected
804 Binding fixed_binding, start_binding;
805 Option<Expression> fixed_exp_opt;
806 Expression fixed_exp, start_exp;
807 Boolean fixed;
808 Option<Expression> min_exp_opt, max_exp_opt;
809
810 function eval_binding
811 input Binding binding;
812 output Option<Expression> result;
813 algorithm
814
2/2
✓ Branch 1 taken 492 times.
✓ Branch 2 taken 4932 times.
5424 if Binding.isBound(binding) then
815 492 result := SOME(Ceval.tryEvalExp(Binding.getExp(binding)));
816 else
817 result := NONE();
818 end if;
819 end eval_binding;
820 algorithm
821
4/4
✓ Branch 0 taken 90774 times.
✓ Branch 1 taken 4909 times.
✓ Branch 3 taken 90279 times.
✓ Branch 4 taken 495 times.
95683 if variability > Variability.CONSTANT and Binding.isBound(binding) then
822 // Parameter with a binding is ok.
823 90279 return;
824 end if;
825
826 // Check if the variable is fixed or not.
827 5404 fixed_binding := Variable.lookupTypeAttribute("fixed", var);
828 5404 fixed_exp_opt := eval_binding(fixed_binding);
829
830
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5404 times.
✓ Branch 2 taken 483 times.
✓ Branch 3 taken 4921 times.
5404 if isSome(fixed_exp_opt) then
831 483 SOME(fixed_exp) := fixed_exp_opt;
832
833
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 483 times.
483 if not Expression.isBoolean(fixed_exp) then
834 ✗ return;
835 end if;
836
837 483 fixed := Expression.isTrue(fixed_exp);
838 else
839 fixed := true;
840 end if;
841
842
2/2
✓ Branch 0 taken 4909 times.
✓ Branch 1 taken 495 times.
5404 if variability == Variability.CONSTANT then
843
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4908 times.
4909 if not fixed then
844 // Constants are not allowed to be non-fixed.
845 2 Error.addSourceMessage(Error.NON_FIXED_CONSTANT,
846 {ComponentRef.toString(var.name)}, var.info);
847
848
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if not settings.relaxedErrorChecking then
849 1 fail();
850 end if;
851 end if;
852
853 // Constants must have binding equations.
854
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4908 times.
4908 if Binding.isUnbound(binding) then
855 ✗ Error.addSourceMessage(Error.NO_CONSTANT_BINDING, {ComponentRef.toString(var.name)}, var.info);
856 ✗ fail();
857 end if;
858 else
859
3/4
✓ Branch 0 taken 482 times.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
495 if fixed and Binding.isUnbound(binding) then
860 13 start_binding := Variable.lookupTypeAttribute("start", var);
861
862
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
13 if Binding.isUnbound(start_binding) then
863 // Fixed parameters must have a binding equation or a start attribute.
864 22 Error.addSourceMessage(Error.UNBOUND_PARAMETER_ERROR,
865 {ComponentRef.toString(var.name)}, var.info);
866
867
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 time.
11 if settings.implicitStartAttribute then
868 // Create a start attribute if it's missing and
869 // --allowNonStandardModelica=implicitParameterStartAttribute is used
870 10 min_exp_opt := eval_binding(Variable.lookupTypeAttribute("min", var));
871 10 max_exp_opt := eval_binding(Variable.lookupTypeAttribute("max", var));
872 10 start_exp := Expression.makeDefaultValue(var.ty, min_exp_opt, max_exp_opt);
873 10 var.binding := Binding.makeFlat(start_exp, Expression.variability(start_exp),
874 NFBinding.Source.GENERATED);
875 elseif not settings.relaxedErrorChecking then
876 1 fail();
877 end if;
878 else
879 6 Error.addSourceMessage(Error.UNBOUND_PARAMETER_WITH_START_VALUE_WARNING,
880 {ComponentRef.toString(var.name), Binding.toString(start_binding)}, var.info);
881 end if;
882 end if;
883 end if;
884 end verifyBinding;
885
886 function getRecordBindings
887 input Binding binding;
888 input array<InstNode> comps;
889 input Prefix prefix;
890 output list<Binding> recordBindings = {};
891 protected
892 Expression binding_exp;
893 Variability var;
894 Binding.Source bind_src;
895 Integer confidence;
896 algorithm
897 5483 binding_exp := Binding.getTypedExp(binding);
898 5483 var := Binding.variability(binding);
899 bind_src := NFBinding.Source.GENERATED;
900 5483 confidence := Binding.confidence(binding);
901
902 // Convert the expressions in the record expression into bindings.
903 recordBindings := match binding_exp
904 case Expression.RECORD()
905
5/6
✓ Branch 0 taken 56700 times.
✓ Branch 1 taken 5477 times.
✓ Branch 2 taken 56700 times.
✓ Branch 3 taken 5477 times.
✓ Branch 5 taken 56700 times.
✗ Branch 6 not taken.
62177 then list(if Expression.isEmpty(e) then
906 // The binding for a record field might be Expression.EMPTY if it comes
907 // from an evaluated function call where it wasn't assigned a value.
908 NFBinding.EMPTY_BINDING
909 else
910 Binding.makeFlat(e, var, bind_src, confidence)
911 for e in binding_exp.elements);
912
913 case Expression.ARRAY()
914 guard Type.isRecord(Type.arrayElementType(Expression.typeOf(binding_exp)))
915
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
24 then list(Binding.makeFlat(Expression.nthRecordElement(i, binding_exp), var, bind_src, confidence)
916 for i in 1:arrayLength(comps));
917
918 else
919 algorithm
920 ✗ Error.terminate(getInstanceName() + " got non-record binding " +
921 Expression.toString(binding_exp), sourceInfo());
922 ✗ then
923 fail();
924 end match;
925
926 10966 Error.assertion(listLength(recordBindings) == arrayLength(comps),
927 getInstanceName() + " got record binding with wrong number of elements for " + Prefix.toString(prefix),
928 sourceInfo());
929 end getRecordBindings;
930
931 function flattenComplexComponent
932 input InstNode node;
933 input Component comp;
934 input Class cls;
935 input Type nodeTy;
936 input Visibility visibility;
937 input Option<Binding> outerBinding;
938 input Prefix prefix;
939 input output list<Variable> vars;
940 input output Sections sections;
941 input DeletedVariables deletedVars;
942 input FlattenSettings settings;
943 protected
944 list<Dimension> dims;
945 ComponentRef name;
946 Binding binding;
947 Option<Binding> opt_binding;
948 Expression binding_exp, binding_exp_eval;
949 Equation eq;
950 Variability comp_var, binding_var;
951 Type ty;
952 Prefix pre;
953 SourceInfo info;
954 algorithm
955 37766 info := InstNode.info(node);
956 37766 ty := flattenType(nodeTy, prefix, info);
957 37766 dims := Type.arrayDims(ty);
958
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 37766 times.
✓ Branch 2 taken 37724 times.
✓ Branch 3 taken 42 times.
37766 binding := if isSome(outerBinding) then Util.getOption(outerBinding) else Component.getBinding(comp);
959
960 // For a complex component with a binding the binding needs to be split into
961 // a binding for each record field, or moved to an initial equation if
962 // splitting the binding fails.
963
2/2
✓ Branch 1 taken 5784 times.
✓ Branch 2 taken 31982 times.
37766 if Binding.isExplicitlyBound(binding) then
964 5784 binding := flattenBinding(binding, prefix);
965 5784 binding_exp := Binding.getTypedExp(binding);
966 5784 binding_var := Binding.variability(binding);
967
968 5784 comp_var := Component.variability(comp);
969
2/2
✓ Branch 0 taken 2921 times.
✓ Branch 1 taken 2863 times.
5784 if comp_var <= Variability.STRUCTURAL_PARAMETER or binding_var <= Variability.STRUCTURAL_PARAMETER then
970 // Constant evaluate parameters that are structural/constant.
971 2921 binding_exp := Ceval.evalExp(binding_exp, Ceval.EvalTarget.new(info, NFInstContext.BINDING));
972 2921 binding_exp := flattenExp(binding_exp, prefix, Binding.getInfo(binding));
973 elseif binding_var == Variability.PARAMETER and Component.isFinal(comp) then
974 // Try to use inlining first.
975 try
976 648 binding_exp := Inline.inlineCallExp(binding_exp, forceInline = true);
977 else
978 end try;
979
980 // If inlining fails, try to evaluate the binding instead.
981
4/4
✓ Branch 1 taken 215 times.
✓ Branch 2 taken 433 times.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 140 times.
648 if not (Expression.isRecord(binding_exp) or Expression.isCref(binding_exp)) then
982 try
983 75 binding_exp_eval := Ceval.tryEvalExp(binding_exp);
984 75 binding_exp_eval := flattenExp(binding_exp_eval, prefix, Binding.getInfo(binding));
985
986 // Throw away the evaluated binding if the number of dimensions no
987 // longer match after evaluation, in case Ceval fails to apply the
988 // subscripts correctly.
989 // TODO: Fix this, it shouldn't be needed.
990
2/2
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 74 times.
75 0 := Type.dimensionDiff(ty, Expression.typeOf(binding_exp_eval));
991 binding_exp := binding_exp_eval;
992 else
993 end try;
994 end if;
995 else
996 2215 binding_exp := SimplifyExp.simplify(binding_exp);
997 end if;
998
999 5784 binding_exp := splitRecordCref(binding_exp);
1000
1001 // TODO: This will probably not work so well if the binding is an array that
1002 // contains record non-literals. In that case we should probably
1003 // create an equation for each non-literal in the array, and pass the
1004 // rest on as usual.
1005
2/2
✓ Branch 1 taken 704 times.
✓ Branch 2 taken 5080 times.
5784 if not Expression.isRecordOrRecordArray(binding_exp) then
1006 // Skip adding the equation when using the new backend, since this only
1007 // occurs when flattening the children of a record instance and will
1008 // conflict with the binding on the actual record instance.
1009
2/2
✓ Branch 0 taken 679 times.
✓ Branch 1 taken 25 times.
704 if not settings.newBackend then
1010 679 name := ComponentRef.prefixCref(node, ty, {}, Prefix.prefix(prefix));
1011 679 eq := Equation.makeEquality(Expression.CREF(ty, name), binding_exp, ty,
1012 ElementSource.createElementSource(info));
1013 679 sections := Sections.prependEquation(eq, sections, isInitial = comp_var <= Variability.PARAMETER);
1014 end if;
1015 opt_binding := SOME(NFBinding.EMPTY_BINDING);
1016 else
1017 5080 binding := Binding.setTypedExp(binding_exp, binding);
1018 opt_binding := SOME(binding);
1019 end if;
1020 else
1021 opt_binding := NONE();
1022 end if;
1023
1024 37766 pre := Prefix.push(node, ty, dims, prefix);
1025
1026 // Flatten the class directly if the component is a scalar, otherwise scalarize it.
1027
2/2
✓ Branch 0 taken 35666 times.
✓ Branch 1 taken 2100 times.
37766 if listEmpty(dims) then
1028 35666 (vars, sections) := flattenClass(cls, pre, visibility, opt_binding, vars, sections, deletedVars, settings);
1029 elseif settings.scalarize then
1030
4/4
✓ Branch 0 taken 2017 times.
✓ Branch 1 taken 2010 times.
✓ Branch 2 taken 2017 times.
✓ Branch 3 taken 2010 times.
4027 dims := list(flattenDimension(d, pre, info) for d in dims);
1031 2010 verifyDimensions(dims, node);
1032 2010 (vars, sections) := flattenArray(cls, dims, pre, visibility, opt_binding, vars, sections, {}, deletedVars, info, settings);
1033 else
1034 90 (vars, sections) := vectorizeArray(cls, ty, dims, pre, visibility, opt_binding, vars, sections, {}, deletedVars, settings);
1035 end if;
1036 end flattenComplexComponent;
1037
1038 function splitRecordCref
1039 input Expression exp;
1040 output Expression outExp;
1041 protected
1042 InstNode cls;
1043 array<InstNode> comps;
1044 ComponentRef cr, field_cr;
1045 Type ty;
1046 list<Expression> fields;
1047 Type cls_ty;
1048 Expression cond;
1049 algorithm
1050 6543 outExp := ExpandExp.expand(exp);
1051
1052 outExp := match outExp
1053 case Expression.CREF(ty = cls_ty as Type.COMPLEX(), cref = cr)
1054 algorithm
1055 2016 cls := Type.complexNode(cls_ty);
1056 2016 comps := ClassTree.getComponents(Class.classTree(InstNode.getClass(cls)));
1057 fields := {};
1058
1059
1/2
✓ Branch 0 taken 2016 times.
✗ Branch 1 not taken.
7558 for i in arrayLength(comps):-1:1 loop
1060 5542 ty := InstNode.getType(comps[i]);
1061 5542 field_cr := ComponentRef.prefixCref(comps[i], ty, {}, cr);
1062 5542 field_cr := flattenCref(field_cr, Prefix.PREFIX(InstNode.EMPTY_NODE(), cr), Absyn.dummyInfo);
1063 5542 fields := Expression.fromCref(field_cr) :: fields;
1064 end for;
1065 2016 then
1066 Expression.makeRecord(InstNode.scopePath(cls), outExp.ty, fields);
1067
1068 case Expression.ARRAY()
1069 algorithm
1070 154 outExp.elements := Array.map(outExp.elements, splitRecordCref);
1071 then
1072 outExp;
1073
1074 case Expression.IF()
1075 guard Expression.variability(outExp.condition) <= Variability.PARAMETER
1076 algorithm
1077 167 cond := Ceval.tryEvalExp(outExp.condition);
1078
1079 // Only mark the condition as structural if it could be evaluated.
1080
1/2
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
167 if not referenceEq(cond, outExp.condition) then
1081 167 Structural.markExp(outExp.condition);
1082 end if;
1083 then
1084 match cond
1085
2/2
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 4 times.
167 case Expression.BOOLEAN() then splitRecordCref(if cond.value then outExp.trueBranch else outExp.falseBranch);
1086 else outExp;
1087 end match;
1088
1089 else exp;
1090 end match;
1091 end splitRecordCref;
1092
1093 function flattenArray
1094 input Class cls;
1095 input list<Dimension> dimensions;
1096 input Prefix prefix;
1097 input Visibility visibility;
1098 input Option<Binding> binding;
1099 input output list<Variable> vars;
1100 input output Sections sections;
1101 input list<Subscript> subscripts = {};
1102 input DeletedVariables deletedVars;
1103 input SourceInfo info;
1104 input FlattenSettings settings;
1105 protected
1106 Dimension dim;
1107 list<Dimension> rest_dims;
1108 Prefix sub_pre;
1109 RangeIterator range_iter;
1110 Expression sub_exp;
1111 list<Subscript> subs;
1112 algorithm
1113
2/2
✓ Branch 0 taken 6176 times.
✓ Branch 1 taken 2024 times.
8200 if listEmpty(dimensions) then
1114 6176 subs := listReverse(subscripts);
1115 6176 sub_pre := Prefix.subscript(subs, prefix);
1116
1117 6176 (vars, sections) := flattenClass(cls, sub_pre, visibility,
1118 subscriptBindingOpt(subs, binding), vars, sections, deletedVars, settings);
1119 else
1120 2024 dim :: rest_dims := dimensions;
1121 2024 dim := flattenDimension(dim, prefix, info);
1122 2024 range_iter := RangeIterator.fromDim(dim, false);
1123
1124
2/2
✓ Branch 1 taken 6190 times.
✓ Branch 2 taken 2024 times.
8214 while RangeIterator.hasNext(range_iter) loop
1125 6190 (range_iter, sub_exp) := RangeIterator.next(range_iter);
1126 12380 (vars, sections) := flattenArray(cls, rest_dims, prefix, visibility,
1127 binding, vars, sections, Subscript.INDEX(sub_exp) :: subscripts, deletedVars, info, settings);
1128 end while;
1129 end if;
1130 end flattenArray;
1131
1132 function vectorizeArray
1133 input Class cls;
1134 input Type cls_ty;
1135 input list<Dimension> dimensions;
1136 input Prefix prefix;
1137 input Visibility visibility;
1138 input Option<Binding> binding;
1139 input output list<Variable> vars;
1140 input output Sections sections;
1141 input list<Subscript> subscripts = {};
1142 input DeletedVariables deletedVars;
1143 input FlattenSettings settings;
1144 protected
1145 list<Variable> vrs;
1146 Sections sects;
1147 list<Equation> eq, ieq;
1148 list<Algorithm> alg, ialg;
1149 algorithm
1150 // Skip the array if any dimension is zero.
1151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
90 if List.any(dimensions, Dimension.isZero) then
1152 ✗ return;
1153 end if;
1154
1155 // if we don't scalarize flatten the class and vectorize it
1156 90 (vrs, sects) := flattenClass(cls, prefix, visibility, binding, {}, Sections.SECTIONS({}, {}, {}, {}), deletedVars, settings);
1157
1158
2/2
✓ Branch 1 taken 361 times.
✓ Branch 2 taken 90 times.
451 for v in listReverse(vrs) loop
1159 // kabdelhak: this would only add 1 layer of dimensions. for nested records it needs to go deeper
1160 // handling it in Variable.expandChildren instead for the new backend
1161
4/4
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 53 times.
✓ Branch 4 taken 251 times.
✓ Branch 5 taken 57 times.
361 if not (settings.newBackend and Type.isRecord(Type.arrayElementType(cls_ty))) then
1162 304 v.ty := Type.liftArrayLeftList(v.ty, dimensions);
1163 end if;
1164 vars := v :: vars;
1165 end for;
1166
1167 // vectorize equations
1168 () := match sects
1169 case Sections.SECTIONS()
1170 algorithm
1171 90 eq := vectorizeEquations(sects.equations, dimensions, prefix, settings);
1172 90 ieq := vectorizeEquations(sects.initialEquations, dimensions, prefix, settings);
1173 90 alg := vectorizeAlgorithms(sects.algorithms, dimensions, prefix);
1174 90 ialg := vectorizeAlgorithms(sects.initialAlgorithms, dimensions, prefix);
1175 90 sections := Sections.prepend(eq, ieq, alg, ialg, sections);
1176 then ();
1177 end match;
1178 end vectorizeArray;
1179
1180 function makeBindingIterators
1181 input ComponentRef prefix;
1182 input list<Dimension> dimensions;
1183 output list<Subscript> subs = {};
1184 protected
1185 Integer index = 0;
1186 ComponentRef iter;
1187 String name;
1188 algorithm
1189 8441 name := "$" + ComponentRef.nodeName(prefix);
1190
1191
2/2
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 8441 times.
9525 for d in dimensions loop
1192 1084 index := index + 1;
1193 1084 iter := ComponentRef.makeIterator(InstNode.newIterator(name + String(index),
1194 Type.INTEGER(), Absyn.dummyInfo));
1195 1084 subs := Subscript.makeIndex(Expression.fromCref(iter)) :: subs;
1196 end for;
1197
1198 8441 subs := listReverseInPlace(subs);
1199 end makeBindingIterators;
1200
1201 function vectorizeBinding
1202 input output Binding binding;
1203 input Prefix prefix;
1204 protected
1205 list<Subscript> subs;
1206 list<InstNode> nodes;
1207 list<Dimension> dims;
1208 Expression exp;
1209 Call array_call;
1210 Type binding_ty;
1211 list<tuple<InstNode, Expression>> iters;
1212 ComponentRef prefix_cr;
1213 Integer confidence;
1214 algorithm
1215
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17805 times.
17805 if not Binding.isBound(binding) then
1216 ✗ return;
1217 end if;
1218
1219 17805 prefix_cr := Prefix.indexedPrefix(prefix);
1220
5/6
✗ Branch 2 not taken.
✓ Branch 3 taken 472 times.
✓ Branch 4 taken 472 times.
✓ Branch 5 taken 17805 times.
✓ Branch 6 taken 472 times.
✓ Branch 7 taken 17805 times.
18277 subs := list(s for s guard Subscript.isIterator(s) in ComponentRef.subscriptsAllFlat(prefix_cr));
1221
1222
2/2
✓ Branch 0 taken 17346 times.
✓ Branch 1 taken 459 times.
17805 if listEmpty(subs) then
1223 17346 return;
1224 end if;
1225
1226 459 exp := Binding.getExp(binding);
1227 459 binding_ty := Binding.getType(binding);
1228
1229 // When replacing split indices we often get expressions such as
1230 // {"m" for $i1 in 1:3}[$x1]. If the subscripts are the same as the subscripts
1231 // in the prefix we can just remove all the subscripts and be done.
1232 () := match exp
1233 case Expression.SUBSCRIPTED_EXP()
1234 guard Subscript.isEqualList(exp.subscripts, subs)
1235 algorithm
1236 7 binding := Binding.makeFlat(exp.exp, Binding.variability(binding), Binding.source(binding), Binding.confidence(binding));
1237 7 return;
1238 then
1239 ();
1240
1241 else ();
1242 end match;
1243
1244 452 nodes := ComponentRef.nodes(prefix_cr);
1245
4/4
✓ Branch 0 taken 959 times.
✓ Branch 1 taken 452 times.
✓ Branch 2 taken 959 times.
✓ Branch 3 taken 452 times.
1411 dims := List.flatten(list(Type.arrayDims(InstNode.getType(n)) for n in nodes));
1246 452 dims := List.lastN(dims, listLength(subs));
1247 // the expression is already split, e.g. CAST(Real, {..}[$x1]), so its own type is the element type
1248 452 binding_ty := Type.liftArrayLeftList(Expression.typeOf(exp), dims);
1249
1250
1/2
✓ Branch 0 taken 452 times.
✗ Branch 1 not taken.
452 if not listEmpty(dims) then
1251
4/4
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 287 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 141 times.
452 if Expression.isLiteral(exp) or not Expression.contains(exp, Expression.isIterator) then
1252
4/4
✓ Branch 2 taken 436 times.
✓ Branch 3 taken 428 times.
✓ Branch 4 taken 436 times.
✓ Branch 5 taken 428 times.
864 array_call := Call.makeTypedCall(NFBuiltinFuncs.FILL_FUNC,
1253 exp :: list(Dimension.sizeExp(d) for d in dims),
1254 Binding.variability(binding), Purity.PURE, binding_ty);
1255 else
1256
7/8
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
53 iters := listReverse((Subscript.toIterator(s), Dimension.toRange(d)) threaded for s in subs, d in dims);
1257
1258 24 array_call := Call.TYPED_ARRAY_CONSTRUCTOR(binding_ty,
1259 Expression.variability(exp), Expression.purity(exp), exp, iters);
1260 end if;
1261
1262 452 exp := Expression.CALL(array_call);
1263 end if;
1264
1265 452 binding := Binding.makeFlat(exp, Binding.variability(binding), Binding.source(binding), Binding.confidence(binding));
1266 end vectorizeBinding;
1267
1268 function fillVectorizedBinding
1269 input output Binding binding;
1270 input Type varType;
1271 protected
1272 Expression bind_exp;
1273 Type bind_ty;
1274 Integer dim_diff;
1275 list<Expression> dim_expl;
1276 algorithm
1277 () := match binding
1278 case Binding.TYPED_BINDING(bindingExp = bind_exp)
1279 algorithm
1280 bind_ty := match bind_exp
1281 case Expression.CREF()
1282 740 then ComponentRef.getSubscriptedType(bind_exp.cref, includeScope = true);
1283 15303 else Expression.typeOf(bind_exp);
1284 end match;
1285
1286 //bind_ty := Expression.typeOf(binding.bindingExp);
1287 16043 dim_diff := Type.dimensionDiff(varType, bind_ty);
1288
1289
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 15805 times.
16043 if dim_diff > 0 then
1290
4/4
✓ Branch 2 taken 246 times.
✓ Branch 3 taken 238 times.
✓ Branch 4 taken 246 times.
✓ Branch 5 taken 238 times.
484 dim_expl := list(Dimension.sizeExp(d) for d in List.firstN(Type.arrayDims(varType), dim_diff));
1291 476 binding.bindingExp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.FILL_FUNC,
1292 binding.bindingExp :: dim_expl, binding.variability, Purity.PURE, varType));
1293 238 binding.bindingType := Expression.typeOf(binding.bindingExp);
1294 end if;
1295 then
1296 ();
1297
1298 else ();
1299 end match;
1300 end fillVectorizedBinding;
1301
1302 function vectorizeEquations
1303 input list<Equation> eql;
1304 input list<Dimension> dimensions;
1305 input Prefix prefix;
1306 input FlattenSettings settings;
1307 output list<Equation> equations = {};
1308 algorithm
1309
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 180 times.
306 for eq in eql loop
1310 126 equations := vectorizeEquation(eq, dimensions, prefix, settings, equations);
1311 end for;
1312
1313 180 equations := listReverseInPlace(equations);
1314 end vectorizeEquations;
1315
1316 function vectorizeEquation
1317 input Equation eqn;
1318 input list<Dimension> dimensions;
1319 input Prefix prefix;
1320 input FlattenSettings settings;
1321 input output list<Equation> equations;
1322 protected
1323 list<Equation> eql;
1324 Type ty;
1325 Expression lhs, rhs;
1326 algorithm
1327 // Flatten with an empty prefix to get rid of any split indices.
1328 126 eql := flattenEquation(eqn, EMPTY_PREFIX, {}, settings);
1329
1330
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
252 for eq in eql loop
1331 equations := match eq
1332 // convert simple equality of crefs to array equality
1333 // kabdelhak: only do it if all subscripts are simple enough
1334 // will lead to complicated code if not index or whole dim
1335 // and we are better off just using for loops for these
1336 case Equation.EQUALITY(lhs = lhs as Expression.CREF(), rhs = rhs as Expression.CREF())
1337 guard(not Flags.getConfigBool(Flags.NEW_BACKEND)
1338 or (List.all(ComponentRef.subscriptsAllWithWholeFlat(lhs.cref), Subscript.isSimple)
1339 and List.all(ComponentRef.subscriptsAllWithWholeFlat(rhs.cref), Subscript.isSimple)))
1340 algorithm
1341 2 ty := Type.liftArrayLeftList(eq.ty, dimensions);
1342 2 lhs := Expression.CREF(ty, lhs.cref);
1343 2 rhs := Expression.CREF(ty, rhs.cref);
1344 2 then Equation.EQUALITY(lhs, rhs, ty, eq.scope, eq.source, eq.scalarizeMode) :: equations;
1345
1346 // Pass Connections.* operators as they are and let the connection
1347 // handling deal with them.
1348 case Equation.NORETCALL(exp = lhs as Expression.CALL())
1349 guard Call.isConnectionsOperator(lhs.call)
1350 then eq :: equations;
1351
1352 // wrap general equation into for loop
1353 else
1354 algorithm
1355 124 eq := vectorizeEquationGeneric(eq, dimensions, prefix);
1356 124 then
1357 splitForLoop(eq, EMPTY_PREFIX, equations, settings);
1358
1359 end match;
1360 end for;
1361 end vectorizeEquation;
1362
1363 function vectorizeEquationGeneric
1364 input Equation eqn;
1365 input list<Dimension> dimensions;
1366 input Prefix prefix;
1367 output Equation vectorizedEqn;
1368 protected
1369 InstNode iter;
1370 list<InstNode> iters;
1371 Expression range;
1372 list<Expression> ranges;
1373 list<Subscript> subs;
1374 NFInstNode.ScopeRef scope;
1375 DAE.ElementSource src;
1376 algorithm
1377 124 (iters, ranges, subs) := makeIterators(Prefix.prefix(prefix), dimensions);
1378 124 subs := listReverseInPlace(subs);
1379 124 vectorizedEqn := Equation.mapExp(eqn, function addIterator(prefix = prefix, subscripts = subs));
1380 124 scope := Equation.scopeCell(eqn);
1381 124 src := Equation.source(eqn);
1382
1383
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 124 times.
263 while not listEmpty(iters) loop
1384 139 iter :: iters := iters;
1385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 range :: ranges := ranges;
1386 139 vectorizedEqn := Equation.FOR(iter, SOME(range), {vectorizedEqn}, scope, src);
1387 end while;
1388 end vectorizeEquationGeneric;
1389
1390 function vectorizeAlgorithms
1391 input list<Algorithm> algs;
1392 input list<Dimension> dimensions;
1393 input Prefix prefix;
1394 output list<Algorithm> algorithms = {};
1395 algorithm
1396
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 180 times.
184 for alg in algs loop
1397 4 algorithms := vectorizeAlgorithm(alg, dimensions, prefix) :: algorithms;
1398 end for;
1399
1400 180 algorithms := listReverseInPlace(algorithms);
1401 end vectorizeAlgorithms;
1402
1403 function vectorizeAlgorithm
1404 input output Algorithm alg;
1405 input list<Dimension> dimensions;
1406 input Prefix prefix;
1407 algorithm
1408 // Flatten with an empty prefix to get rid of any split indices.
1409 4 alg.statements := flattenStatements(alg.statements, EMPTY_PREFIX);
1410
1411 alg := match alg
1412 local
1413 InstNode iter;
1414 list<InstNode> iters;
1415 Expression range;
1416 list<Expression> ranges;
1417 list<Subscript> subs;
1418 list<Statement> body;
1419
1420 // let simple assignment as is
1421 case Algorithm.ALGORITHM(statements = {Statement.ASSIGNMENT(lhs = Expression.CREF(), rhs = Expression.CREF())})
1422 then alg;
1423
1424 // wrap general algorithm into for loop
1425 else
1426 algorithm
1427 4 (iters, ranges, subs) := makeIterators(Prefix.prefix(prefix), dimensions);
1428 4 subs := listReverseInPlace(subs);
1429 4 body := Statement.mapExpList(alg.statements, function addIterator(prefix = prefix, subscripts = subs));
1430
1431
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while not listEmpty(iters) loop
1432 4 iter :: iters := iters;
1433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 range :: ranges := ranges;
1434 4 body := {Statement.FOR(iter, SOME(range), body, Statement.ForType.NORMAL(), alg.source, {})};
1435 end while;
1436 4 then
1437 Algorithm.ALGORITHM(body, alg.inputs, alg.outputs, NONE(), alg.scope, alg.source); // ToDo: update inputs, outputs?
1438 end match;
1439 end vectorizeAlgorithm;
1440
1441 public function makeIterators
1442 input ComponentRef prefix;
1443 input list<Dimension> dimensions;
1444 output list<InstNode> iterators = {};
1445 output list<Expression> ranges = {};
1446 output list<Subscript> subscripts = {};
1447 protected
1448 InstNode prefix_node, iter;
1449 Expression range;
1450 Subscript sub;
1451 algorithm
1452 169 prefix_node := ComponentRef.node(prefix);
1453
1454
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 169 times.
359 for dim in dimensions loop
1455 190 iter := InstNode.newUniqueIterator(InstNode.info(prefix_node));
1456 iterators := iter :: iterators;
1457
1458 190 range := Expression.makeRange(Expression.INTEGER(1), NONE(), Dimension.sizeExp(dim));
1459 ranges := range :: ranges;
1460
1461 190 sub := Subscript.INDEX(Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER())));
1462 subscripts := sub :: subscripts;
1463 end for;
1464 end makeIterators;
1465
1466 protected
1467 function addIterator
1468 input output Expression exp;
1469 input Prefix prefix;
1470 input list<Subscript> subscripts;
1471 algorithm
1472 276 exp := Expression.map(exp, function addIterator_traverse(prefix = prefix, subscripts = subscripts));
1473 end addIterator;
1474
1475 function addIterator_traverse
1476 input output Expression exp;
1477 input Prefix prefix;
1478 input list<Subscript> subscripts;
1479 protected
1480 ComponentRef ref = Prefix.prefix(prefix);
1481 String restString, prefixString = ComponentRef.toString(ref);
1482 algorithm
1483 exp := match exp
1484 local
1485 ComponentRef restCref;
1486 case Expression.CREF(cref = ComponentRef.CREF(restCref = restCref))
1487 algorithm
1488 373 restString := ComponentRef.toString(restCref);
1489
2/2
✓ Branch 1 taken 339 times.
✓ Branch 2 taken 34 times.
373 if StringUtil.startsWith(restString, prefixString) then
1490 339 exp.cref := mergeIterator(exp.cref, ref, subscripts);
1491 end if;
1492 then
1493 exp;
1494 else exp;
1495 end match;
1496 end addIterator_traverse;
1497
1498 function mergeIterator
1499 input output ComponentRef cref;
1500 input ComponentRef ref;
1501 input list<Subscript> subscripts;
1502 algorithm
1503 cref := match cref
1504 case ComponentRef.CREF() algorithm
1505
2/2
✓ Branch 1 taken 339 times.
✓ Branch 2 taken 489 times.
828 if ComponentRef.isEqual(cref, ref) then
1506 339 cref.subscripts := listAppend(cref.subscripts, subscripts);
1507 else
1508 489 cref.restCref := mergeIterator(cref.restCref, ref, subscripts);
1509 end if;
1510 then cref;
1511 else cref;
1512 end match;
1513 end mergeIterator;
1514
1515 function containsPrefix
1516 input Expression exp;
1517 input Prefix prefix;
1518 output Boolean contains;
1519 algorithm
1520 17 contains := Expression.fold(exp, function containsPrefix_traverse(prefix = prefix), false);
1521 end containsPrefix;
1522
1523 function containsPrefix_traverse
1524 input Expression exp;
1525 input output Boolean contains;
1526 input Prefix prefix;
1527 protected
1528 String restString, prefixString = ComponentRef.toString(Prefix.prefix(prefix));
1529 algorithm
1530 () := match exp
1531 local
1532 ComponentRef restCref;
1533 case Expression.CREF(cref = ComponentRef.CREF(restCref = restCref))
1534 algorithm
1535 7 restString := ComponentRef.toString(restCref);
1536
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
7 if StringUtil.startsWith(restString, prefixString) then
1537 contains := true;
1538 end if;
1539 then
1540 ();
1541 else ();
1542 end match;
1543 end containsPrefix_traverse;
1544
1545 function subscriptBindingOpt
1546 input list<Subscript> subscripts;
1547 input output Option<Binding> binding;
1548 protected
1549 Binding b;
1550 Expression exp;
1551 Type ty;
1552 algorithm
1553
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6176 times.
✓ Branch 2 taken 556 times.
✓ Branch 3 taken 5620 times.
6176 if isSome(binding) then
1554
3/3
✓ Branch 0 taken 497 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 23 times.
556 SOME(b) := binding;
1555
1556 binding := match b
1557 case Binding.TYPED_BINDING(bindingExp = exp, bindingType = ty)
1558 algorithm
1559 497 b.bindingExp := Expression.applySubscripts(subscripts, exp);
1560 497 b.bindingType := Type.arrayElementType(ty);
1561 then
1562 SOME(b);
1563
1564 case Binding.FLAT_BINDING(bindingExp = exp)
1565 algorithm
1566 36 b.bindingExp := Expression.applySubscripts(subscripts, exp);
1567 then
1568 SOME(b);
1569
1570 else binding;
1571 end match;
1572 end if;
1573 end subscriptBindingOpt;
1574
1575 public function flattenBinding
1576 input output Binding binding;
1577 input Prefix prefix;
1578 input Boolean isTypeAttribute = false;
1579 protected
1580 SourceInfo info;
1581 algorithm
1582 binding := match binding
1583 case Binding.UNBOUND() then binding;
1584
1585 case Binding.TYPED_BINDING()
1586 algorithm
1587
2/2
✓ Branch 0 taken 5417 times.
✓ Branch 1 taken 600710 times.
606127 if binding.isFlattened then
1588 5417 return;
1589 end if;
1590
1591 600710 info := Binding.getInfo(binding);
1592 600710 binding.bindingExp := flattenExp(binding.bindingExp, prefix, info);
1593 600709 binding.bindingType := flattenType(binding.bindingType, prefix, info);
1594 600709 binding.isFlattened := true;
1595
2/2
✓ Branch 1 taken 17805 times.
✓ Branch 2 taken 582904 times.
600709 then
1596 if Prefix.isIndexed(prefix) then vectorizeBinding(binding, prefix) else binding;
1597
1598 // CEVAL_BINDINGs are temporary bindings generated by the constant
1599 // evaluation and no longer needed after flattening.
1600 case Binding.CEVAL_BINDING() then NFBinding.EMPTY_BINDING;
1601 case Binding.FLAT_BINDING() then binding;
1602
1603 case Binding.INVALID_BINDING()
1604 algorithm
1605 1 Error.addTotalMessages(binding.errors);
1606 1 then
1607 fail();
1608
1609 else
1610 algorithm
1611 ✗ Error.terminate(getInstanceName() + " got untyped binding.", sourceInfo());
1612 ✗ then
1613 fail();
1614
1615 end match;
1616 end flattenBinding;
1617
1618 public function flattenExp
1619 input output Expression exp;
1620 input Prefix prefix;
1621 input SourceInfo info;
1622 algorithm
1623 exp := match exp
1624 case Expression.CREF(cref = ComponentRef.CREF())
1625 algorithm
1626 834326 exp.cref := ComponentRef.mapExpShallow(exp.cref, function flattenExp(prefix = prefix, info = info));
1627 417163 exp.cref := flattenCref(exp.cref, prefix, info);
1628 417163 exp.ty := flattenType(exp.ty, prefix, info);
1629
4/4
✓ Branch 1 taken 26356 times.
✓ Branch 2 taken 390807 times.
✓ Branch 4 taken 566 times.
✓ Branch 5 taken 25790 times.
417163 then
1630 // the same size parameter everywhere: in loop ranges and indices as in
1631 // the dimensions, see resizableDimensionAlias
1632 if Type.isInteger(exp.ty) and Flags.getConfigBool(Flags.RESIZABLE_ARRAYS)
1633 then resizableDimensionAlias(exp, prefix, info) else exp;
1634
1635 case Expression.SUBSCRIPTED_EXP(split = true)
1636 74757 then Expression.mapShallow(
1637 replaceSplitIndices(exp.exp, exp.subscripts, prefix, info),
1638 function flattenExp(prefix = prefix, info = info));
1639
1640 case Expression.IF(ty = Type.CONDITIONAL_ARRAY())
1641 52 then flattenConditionalArrayIfExp(exp, prefix, info);
1642
1643 case Expression.INSTANCE_NAME()
1644 58 then Expression.STRING(Prefix.instanceName(prefix));
1645
1646 1542552 else Expression.mapShallow(exp, function flattenExp(prefix = prefix, info = info));
1647 end match;
1648
1649 2034581 exp := flattenExpType(exp, prefix, info);
1650 end flattenExp;
1651
1652 function replaceSplitIndices
1653 input output Expression exp;
1654 input list<Subscript> subscripts;
1655 input Prefix prefix;
1656 input SourceInfo info;
1657 protected
1658 list<Subscript> subs = subscripts, cr_subs;
1659 Integer index;
1660 InstNode cr_node;
1661 algorithm
1662
2/2
✓ Branch 2 taken 188576 times.
✓ Branch 3 taken 74757 times.
263333 for cr in ComponentRef.toListReverse(Prefix.indexedPrefix(prefix)) loop
1663 188576 cr_subs := ComponentRef.getSubscripts(cr);
1664
1665
2/2
✓ Branch 0 taken 9125 times.
✓ Branch 1 taken 179451 times.
188576 if not listEmpty(cr_subs) then
1666 index := 1;
1667 9125 cr_node := ComponentRef.node(cr);
1668
1669
2/2
✓ Branch 1 taken 9133 times.
✓ Branch 2 taken 9125 times.
18258 for s in cr_subs loop
1670 9133 subs := List.replaceOnTrue(s, subs,
1671 function replaceSplitIndices2(node = cr_node, index = index));
1672 9133 index := index + 1;
1673 end for;
1674 end if;
1675 end for;
1676
1677 74757 subs := Subscript.expandSplitIndices(subs);
1678 74757 exp := Expression.applySubscripts(subs, exp);
1679 74757 exp := flattenExp(exp, prefix, info);
1680 end replaceSplitIndices;
1681
1682 function replaceSplitIndices2
1683 input Subscript sub;
1684 input InstNode node;
1685 input Integer index;
1686 output Boolean replace;
1687 algorithm
1688 replace := match sub
1689 case Subscript.SPLIT_INDEX()
1690
4/4
✓ Branch 0 taken 9131 times.
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 6944 times.
✓ Branch 5 taken 2187 times.
9133 then sub.dimIndex == index and InstNode.refEqual(InstNode.borrow(sub.node), node);
1691 else false;
1692 end match;
1693 end replaceSplitIndices2;
1694
1695 function flattenCref
1696 input output ComponentRef cref;
1697 input Prefix prefix;
1698 input SourceInfo info;
1699 algorithm
1700 422705 cref := Prefix.apply(prefix, cref);
1701
1702
2/2
✓ Branch 1 taken 3073 times.
✓ Branch 2 taken 419632 times.
422705 if ComponentRef.hasSplitSubscripts(cref) then
1703 3073 cref := flattenCrefSplitSubscripts(cref, prefix);
1704 end if;
1705
1706 422705 cref := ComponentRef.mapTypes(cref, function flattenType(prefix = prefix, info = info));
1707 end flattenCref;
1708
1709 function flattenCrefSplitSubscripts
1710 input output ComponentRef cref;
1711 input Prefix prefix;
1712 protected
1713 type SubscriptList = list<Subscript>;
1714 UnorderedMap<InstNode, SubscriptList> sub_map;
1715 algorithm
1716 3073 sub_map := UnorderedMap.new<SubscriptList>(InstNode.hash, InstNode.refEqual);
1717
1718
2/2
✓ Branch 2 taken 7707 times.
✓ Branch 3 taken 3073 times.
10780 for cr in ComponentRef.toListReverse(Prefix.indexedPrefix(prefix)) loop
1719
2/2
✓ Branch 1 taken 2367 times.
✓ Branch 2 taken 5340 times.
7707 if ComponentRef.hasSubscripts(cr) then
1720 2367 UnorderedMap.addUnique(ComponentRef.node(cr), ComponentRef.getSubscripts(cr), sub_map);
1721 end if;
1722 end for;
1723
1724 3073 cref := ComponentRef.mapSubscripts(cref, function flattenCrefSplitSubscripts2(subMap = sub_map));
1725 3073 cref := ComponentRef.simplifySubscripts(cref, true);
1726 end flattenCrefSplitSubscripts;
1727
1728 function flattenCrefSplitSubscripts2
1729 input output Subscript sub;
1730 input UnorderedMap<InstNode, list<Subscript>> subMap;
1731 algorithm
1732 sub := match sub
1733 local
1734 list<Subscript> subs;
1735
1736 case Subscript.SPLIT_INDEX()
1737 algorithm
1738 3073 subs := UnorderedMap.getOrDefault(InstNode.borrow(sub.node), subMap, {});
1739
2/2
✓ Branch 1 taken 1694 times.
✓ Branch 2 taken 1379 times.
3073 then
1740 if sub.dimIndex > listLength(subs) then Subscript.WHOLE() else listGet(subs, sub.dimIndex);
1741
1742 else sub;
1743 end match;
1744 end flattenCrefSplitSubscripts2;
1745
1746 function flattenConditionalArrayIfExp
1747 input output Expression exp;
1748 input Prefix prefix;
1749 input SourceInfo info;
1750 protected
1751 Type ty;
1752 Expression cond, tb, fb;
1753 Variability cond_var;
1754 algorithm
1755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 Expression.IF(ty = ty, condition = cond, trueBranch = tb, falseBranch = fb) := exp;
1756 52 cond := flattenExp(cond, prefix, info);
1757 52 cond_var := Expression.variability(cond);
1758
1759
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 if Type.isConditionalArray(ty) then
1760 // An if-expression where the branches are array expression with different
1761 // dimensions, evaluate the condition and try to select one of the branches.
1762 52 Structural.markExp(cond);
1763 52 cond := Ceval.tryEvalExp(cond);
1764
1765 exp := match cond
1766 case Expression.BOOLEAN()
1767 algorithm
1768
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
51 if not Type.isMatchedBranch(cond.value, ty) then
1769 // The branch with the incompatible dimensions was chosen, print an
1770 // error and fail.
1771 ✗ (tb, fb) := Util.swap(cond.value, fb, tb);
1772 ✗ Error.addSourceMessage(Error.ARRAY_DIMENSION_MISMATCH,
1773 {Expression.toString(tb), Type.toString(Expression.typeOf(tb)),
1774 Dimension.toStringList(Type.arrayDims(Expression.typeOf(fb)), brackets = false)}, info);
1775 ✗ fail();
1776 end if;
1777
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 48 times.
51 then
1778 flattenExp(if cond.value then tb else fb, prefix, info);
1779
1780 else
1781 algorithm
1782 // The condition couldn't be evaluated, print an error and fail.
1783 5 Error.addSourceMessage(Error.TYPE_MISMATCH_IF_EXP,
1784 {"", Expression.toString(tb), Type.toString(Expression.typeOf(tb)),
1785 Expression.toString(fb), Type.toString(Expression.typeOf(fb))}, info);
1786 1 then
1787 fail();
1788 end match;
1789 elseif Expression.variability(cond) == Variability.PARAMETER then
1790 ✗ Structural.markExp(cond);
1791 ✗ tb := flattenExp(tb, prefix, info);
1792 ✗ fb := flattenExp(fb, prefix, info);
1793 ✗ ty := flattenType(ty, prefix, info);
1794 ✗ exp := Expression.IF(ty, cond, tb, fb);
1795 end if;
1796 end flattenConditionalArrayIfExp;
1797
1798 function flattenExpType
1799 input output Expression exp;
1800 input Prefix prefix;
1801 input SourceInfo info;
1802 protected
1803 Type ty;
1804 algorithm
1805 2034581 ty := Expression.typeOf(exp);
1806
1807
2/2
✓ Branch 1 taken 1736072 times.
✓ Branch 2 taken 298509 times.
2034581 if Type.isArray(ty) then
1808 298509 ty := flattenType(ty, prefix, info);
1809 298509 exp := Expression.setType(ty, exp);
1810 end if;
1811 end flattenExpType;
1812
1813 function flattenType
1814 input output Type ty;
1815 input Prefix prefix;
1816 input SourceInfo info;
1817 algorithm
1818 2933264 ty := Type.mapDims(ty, function flattenDimension(prefix = prefix, info = info));
1819 end flattenType;
1820
1821 function flattenDimension
1822 input output Dimension dim;
1823 input Prefix prefix;
1824 input SourceInfo info;
1825 protected
1826 Expression exp, alias;
1827 algorithm
1828 dim := match dim
1829 case Dimension.EXP()
1830 algorithm
1831 2807 exp := flattenExp(dim.exp, prefix, info);
1832
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2807 times.
2807 if Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) then
1833 ✗ exp := resizableDimensionAlias(exp, prefix, info);
1834 end if;
1835 2807 then Dimension.fromExp(exp, dim.var);
1836
1837 // a resizable dimension given by an alias of another size parameter, see
1838 // resizableDimensionAlias (flattenExp replaces the alias)
1839 case Dimension.RESIZABLE() guard Flags.getConfigBool(Flags.RESIZABLE_ARRAYS)
1840 algorithm
1841 365 exp := flattenExp(dim.exp, prefix, info);
1842
2/2
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 201 times.
365 then if sameComponent(exp, dim.exp) then dim else Dimension.fromExp(exp, dim.var);
1843
1844 else dim;
1845 end match;
1846 end flattenDimension;
1847
1848 function sameComponent
1849 "true if both expressions are crefs of the same component"
1850 input Expression exp1;
1851 input Expression exp2;
1852 output Boolean b;
1853 algorithm
1854 b := match (exp1, exp2)
1855 case (Expression.CREF(cref = ComponentRef.CREF()), Expression.CREF(cref = ComponentRef.CREF()))
1856 209 then InstNode.refEqual(ComponentRef.node(exp1.cref), ComponentRef.node(exp2.cref));
1857 else false;
1858 end match;
1859 end sameComponent;
1860
1861 function resizableDimensionAlias
1862 "A dimension given by a parameter of an array of components (e.g. b[N] in
1863 s[M](each N = K) is s.N, one size for each element) is an alias of the
1864 binding if all elements get the same value: the dimension is K then. Without
1865 scalarization all elements of an array have to have the same size anyway.
1866 A dimension given by a parameter of a component bound to another parameter
1867 (s.N for s(N = N)) is that parameter. Otherwise the dimension stays as it is."
1868 input Expression exp;
1869 input Prefix prefix;
1870 input SourceInfo info;
1871 output Expression outExp = exp;
1872 protected
1873 InstNode node;
1874 Binding binding;
1875 Expression bexp;
1876 algorithm
1877 () := match exp
1878 // ComponentRef.node, the Rust port stores a handle in the record field
1879 case Expression.CREF(cref = ComponentRef.CREF())
1880 guard InstNode.isComponent(ComponentRef.node(exp.cref)) and ComponentRef.variability(exp.cref) <= Variability.NON_STRUCTURAL_PARAMETER
1881 algorithm
1882 503 node := ComponentRef.node(exp.cref);
1883 try
1884 503 binding := Component.getBinding(InstNode.component(node));
1885
2/2
✓ Branch 1 taken 460 times.
✓ Branch 2 taken 43 times.
503 if Binding.isBound(binding) then
1886 460 bexp := Binding.getTypedExp(flattenBinding(binding, prefix));
1887
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 460 times.
460 if isInComponentArray(exp.cref) then
1888 // a parameter of an array of components, e.g. s.N or s[$s1].N for s[M]
1889 ✗ bexp := uniformArrayElement(bexp);
1890 ✗ if not Type.isArray(Expression.typeOf(bexp)) then
1891 outExp := bexp;
1892 end if;
1893 elseif not ComponentRef.isEmpty(ComponentRef.rest(exp.cref)) and Expression.isCref(bexp) and
1894 not Expression.isIterator(bexp) and Type.isInteger(Expression.typeOf(bexp)) and
1895 ComponentRef.isResizable(Expression.toCref(bexp)) then
1896 // a parameter of a component bound to another resizable parameter, e.g. s.N for s(N = N)
1897 10 outExp := resizableDimensionAlias(bexp, prefix, info);
1898 end if;
1899 end if;
1900 else
1901 end try;
1902 then ();
1903 else ();
1904 end match;
1905 end resizableDimensionAlias;
1906
1907 function uniformArrayElement
1908 "The value of all elements of an array expression if they are all the same:
1909 the body of an array constructor that does not depend on its iterators, or
1910 the expression itself if it is no array. Fails otherwise."
1911 input Expression exp;
1912 output Expression elem;
1913 algorithm
1914 elem := match exp
1915 local
1916 Expression body;
1917 list<tuple<InstNode, Expression>> iters;
1918 case Expression.CALL(call = Call.TYPED_ARRAY_CONSTRUCTOR(exp = body, iters = iters))
1919 guard not List.any(iters, function iteratorOccursIn(exp = body))
1920 ✗ then uniformArrayElement(body);
1921 case Expression.CALL() guard Call.isNamed(exp.call, "fill")
1922 ✗ then uniformArrayElement(listHead(Call.arguments(exp.call)));
1923 case _ guard not Type.isArray(Expression.typeOf(exp)) then exp;
1924 end match;
1925 end uniformArrayElement;
1926
1927 function isInComponentArray
1928 "true if a cref is a component of an array of components, e.g. s.N for s[M]"
1929 input ComponentRef cref;
1930 output Boolean b;
1931 protected
1932 ComponentRef rest;
1933 algorithm
1934 460 rest := ComponentRef.rest(cref);
1935
3/4
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 442 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
460 b := not ComponentRef.isEmpty(rest) and Type.isArray(ComponentRef.nodeType(ComponentRef.stripSubscripts(rest)));
1936 end isInComponentArray;
1937
1938 function iteratorOccursIn
1939 input tuple<InstNode, Expression> iter;
1940 input Expression exp;
1941 output Boolean b = Expression.containsIterator(exp, Util.tuple21(iter));
1942 end iteratorOccursIn;
1943
1944 function flattenSections
1945 input Sections sections;
1946 input Prefix prefix;
1947 input output Sections accumSections;
1948 input FlattenSettings settings;
1949 algorithm
1950 () := match sections
1951 local
1952 list<Equation> eq, ieq;
1953 list<Algorithm> alg, ialg;
1954
1955 case Sections.SECTIONS()
1956 algorithm
1957 9741 eq := flattenEquations(sections.equations, prefix, settings);
1958 9740 ieq := flattenEquations(sections.initialEquations, prefix, settings);
1959 9740 alg := flattenAlgorithms(sections.algorithms, prefix);
1960 9740 ialg := flattenAlgorithms(sections.initialAlgorithms, prefix);
1961 9740 accumSections := Sections.prepend(eq, ieq, alg, ialg, accumSections);
1962 then
1963 ();
1964
1965 else ();
1966 end match;
1967 end flattenSections;
1968
1969 function flattenEquations
1970 input list<Equation> eql;
1971 input Prefix prefix;
1972 input FlattenSettings settings;
1973 output list<Equation> equations = {};
1974 algorithm
1975
2/2
✓ Branch 0 taken 87850 times.
✓ Branch 1 taken 34468 times.
122318 for eq in eql loop
1976 87850 equations := flattenEquation(eq, prefix, equations, settings);
1977 end for;
1978 end flattenEquations;
1979
1980 function flattenEquation
1981 input Equation eq;
1982 input Prefix prefix;
1983 input output list<Equation> equations;
1984 input FlattenSettings settings;
1985 protected
1986 SourceInfo info = Equation.info(eq);
1987 algorithm
1988 equations := match eq
1989 local
1990 Expression e1, e2, e3;
1991 Type ty;
1992 list<Equation> eql;
1993
1994 case Equation.EQUALITY()
1995 algorithm
1996 60524 e1 := flattenExp(eq.lhs, prefix, info);
1997 60524 e2 := flattenExp(eq.rhs, prefix, info);
1998 60524 ty := flattenType(eq.ty, prefix, info);
1999 60524 checkEqualityEquation(e1, e2, eq.source);
2000 60523 then
2001 Equation.EQUALITY(e1, e2, ty, eq.scope, eq.source, eq.scalarizeMode) :: equations;
2002
2003 case Equation.FOR()
2004 algorithm
2005
2/2
✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 200 times.
1526 if settings.scalarize then
2006 1326 eql := unrollForLoop(eq, prefix, equations, settings);
2007 else
2008 200 eql := splitForLoop(eq, prefix, equations, settings);
2009 end if;
2010 then eql;
2011
2012 case Equation.CONNECT()
2013 algorithm
2014 13431 e1 := flattenExp(eq.lhs, prefix, info);
2015 13431 e2 := flattenExp(eq.rhs, prefix, info);
2016 13431 then
2017 Equation.CONNECT(e1, e2, eq.scope, eq.source) :: equations;
2018
2019 case Equation.IF()
2020 7212 then flattenIfEquation(eq, prefix, equations, settings);
2021
2022 case Equation.WHEN()
2023 algorithm
2024
4/4
✓ Branch 0 taken 367 times.
✓ Branch 1 taken 326 times.
✓ Branch 2 taken 367 times.
✓ Branch 3 taken 326 times.
1019 eq.branches := list(flattenEqBranch(b, prefix, info, settings) for b in eq.branches);
2025 then
2026 eq :: equations;
2027
2028 case Equation.ASSERT()
2029 algorithm
2030 3858 e1 := flattenExp(eq.condition, prefix, info);
2031 3858 e2 := flattenExp(eq.message, prefix, info);
2032 3858 e3 := flattenExp(eq.level, prefix, info);
2033 3858 then
2034 Equation.ASSERT(e1, e2, e3, eq.scope, eq.source) :: equations;
2035
2036 case Equation.TERMINATE()
2037 algorithm
2038 6 e1 := flattenExp(eq.message, prefix, info);
2039 6 then
2040 Equation.TERMINATE(e1, eq.scope, eq.source) :: equations;
2041
2042 case Equation.REINIT()
2043 algorithm
2044 32 e1 := flattenExp(eq.cref, prefix, info);
2045 32 e2 := flattenExp(eq.reinitExp, prefix, info);
2046 32 then
2047 Equation.REINIT(e1, e2, eq.scope, eq.source) :: equations;
2048
2049 case Equation.NORETCALL()
2050 algorithm
2051 1061 e1 := flattenExp(eq.exp, prefix, info);
2052 1061 then
2053 Equation.NORETCALL(e1, eq.scope, eq.source) :: equations;
2054
2055 else eq :: equations;
2056 end match;
2057 end flattenEquation;
2058
2059 function checkEqualityEquation
2060 input Expression lhs;
2061 input Expression rhs;
2062 input DAE.ElementSource src;
2063 protected
2064 Expression out0, out1, pos_vel;
2065 Call call;
2066 algorithm
2067 () := match (lhs, rhs)
2068 // spatialDistribution has special rules on how its outputs can be used.
2069 case (Expression.TUPLE(elements = {out0, out1}), Expression.CALL(call))
2070 guard (Expression.isWildCref(out0) or Expression.isWildCref(out1)) and
2071 Call.isNamed(call, "spatialDistribution")
2072 algorithm
2073 // The second output may not be ignored.
2074
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if Expression.isWildCref(out1) then
2075 ✗ Error.addSourceMessage(Error.SPATIAL_DISTRIBUTION_IGNORED_OUT1, {}, ElementSource.getInfo(src));
2076 ✗ fail();
2077 end if;
2078
2079 // The first output may only be ignored if positiveVelocity is true.
2080
7/14
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
2 {_, _, _, pos_vel, _, _} := Call.arguments(call);
2081 2 Structural.markExp(pos_vel);
2082 2 pos_vel := Ceval.tryEvalExp(pos_vel);
2083
2084
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if not Expression.isTrue(pos_vel) then
2085 1 Error.addSourceMessage(Error.SPATIAL_DISTRIBUTION_IGNORED_OUT0, {}, ElementSource.getInfo(src));
2086 1 fail();
2087 end if;
2088 then
2089 ();
2090
2091 // spatialDistribution may be wrapped in a noEvent.
2092 case (Expression.TUPLE(), Expression.CALL(call))
2093 guard Call.isNamed(call, "noEvent")
2094 algorithm
2095 1 checkEqualityEquation(lhs, listHead(Call.arguments(call)), src);
2096 then
2097 ();
2098
2099 else ();
2100 end match;
2101 end checkEqualityEquation;
2102
2103 function flattenIfEquation
2104 input Equation eq;
2105 input Prefix prefix;
2106 input output list<Equation> equations;
2107 input FlattenSettings settings;
2108 protected
2109 Equation.Branch branch;
2110 list<Equation.Branch> branches, bl = {};
2111 Expression cond;
2112 list<Equation> eql;
2113 Variability var;
2114 Boolean has_connect, should_eval = false, structural = true;
2115 DAE.ElementSource src;
2116 SourceInfo info;
2117 Ceval.EvalTarget target;
2118 NFInstNode.ScopeRef scope;
2119 algorithm
2120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7212 times.
7212 Equation.IF(branches = branches, scope = scope, source = src) := eq;
2121 7212 has_connect := Equation.contains(eq, Equation.isConnection);
2122 7212 info := Equation.info(eq);
2123
2124 // Print errors for unbound constants/parameters if the if-equation contains
2125 // connects, since we must select a branch in that case.
2126
2/2
✓ Branch 0 taken 390 times.
✓ Branch 1 taken 6822 times.
7212 target := if has_connect then Ceval.EvalTarget.new(info) else NFCeval.noTarget;
2127
2128
2/2
✓ Branch 0 taken 11067 times.
✓ Branch 1 taken 7212 times.
18279 while not listEmpty(branches) loop
2129 11067 branch :: branches := branches;
2130
2131 bl := match branch
2132 case Equation.Branch.BRANCH(cond, var, eql)
2133 algorithm
2134 // Flatten the condition and body of the branch.
2135 11062 cond := flattenExp(cond, prefix, info);
2136
2137 // Evaluate structural conditions.
2138
2/2
✓ Branch 0 taken 9677 times.
✓ Branch 1 taken 1385 times.
11062 if var <= Variability.STRUCTURAL_PARAMETER then
2139
2/2
✓ Branch 1 taken 9676 times.
✓ Branch 2 taken 1 time.
9677 if Expression.isPure(cond) then
2140
2/2
✓ Branch 0 taken 754 times.
✓ Branch 1 taken 8922 times.
9676 if has_connect then
2141 // If-equations containing connects must be evaluated, but with
2142 // the new backend it needs to be done after vectorization.
2143 754 should_eval := not settings.newBackend;
2144 structural := true;
2145 elseif settings.minimalEval then
2146 // Don't evaluate if --evaluateStructuralParameters=strictlyNecessary
2147 should_eval := false;
2148 structural := false;
2149 elseif settings.scalarize then
2150 // Evaluate if scalarization is turned on.
2151 should_eval := true;
2152 elseif settings.newBackend or Expression.contains(cond, Expression.isIterator) then
2153 // Don't evaluate if the new backend is used or the expression contains iterators.
2154 should_eval := false;
2155 // The condition needs to be vectorized before we evaluate it for the new backend,
2156 // so mark it as structural so it gets evaluated later instead.
2157 611 structural := settings.newBackend;
2158 else
2159 // TODO: The condition shouldn't be evaluated if scalarization is
2160 // turned off since that breaks vectorizeEquation, but
2161 // turning it off completely doesn't work yet either.
2162 should_eval := true;
2163 end if;
2164
2165 // Mark the expression if it's structural. If we evaluate it it's always structural.
2166
1/2
✓ Branch 0 taken 9676 times.
✗ Branch 1 not taken.
9676 if structural or should_eval then
2167 9676 Structural.markExp(cond);
2168 end if;
2169
2170
2/2
✓ Branch 0 taken 9020 times.
✓ Branch 1 taken 656 times.
9676 if should_eval then
2171 9020 cond := Ceval.tryEvalExp(cond, target);
2172 9020 cond := flattenExp(cond, prefix, info);
2173 end if;
2174 end if;
2175
2176 // Conditions in an if-equation that contains connects must be possible to evaluate.
2177
5/6
✓ Branch 1 taken 515 times.
✓ Branch 2 taken 9162 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 492 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 23 times.
9677 if not Expression.isBoolean(cond) and has_connect and not settings.newBackend then
2178 ✗ Error.addInternalError(
2179 "Failed to evaluate branch condition in if equation containing connect equations: `" +
2180 Expression.toString(cond) + "`", info);
2181 ✗ fail();
2182 end if;
2183 end if;
2184
2185
2/2
✓ Branch 1 taken 5501 times.
✓ Branch 2 taken 5561 times.
11062 if Expression.isTrue(cond) then
2186 // The condition is true and the branch will thus always be selected
2187 // if reached, so we can discard the remaining branches.
2188 branches := {};
2189 5501 eql := flattenEquations(eql, prefix, settings);
2190
2191
2/2
✓ Branch 0 taken 4755 times.
✓ Branch 1 taken 746 times.
5501 if listEmpty(bl) then
2192 // If we haven't collected any other branches yet, replace the if-equation with this branch.
2193 4755 equations := listAppend(eql, equations);
2194 else
2195 // Otherwise, append this branch.
2196 746 bl := Equation.makeBranch(cond, listReverseInPlace(eql), var) :: bl;
2197 end if;
2198 elseif not Expression.isFalse(cond) then
2199 // Only add the branch to the list of branches if the condition is not
2200 // literal false, otherwise just drop it since it will never trigger.
2201 1900 eql := flattenEquations(eql, prefix, settings);
2202 1900 bl := Equation.makeBranch(cond, listReverseInPlace(eql), var) :: bl;
2203 end if;
2204 then
2205 bl;
2206
2207 // An invalid branch must have a false condition, anything else is an error.
2208 case Equation.Branch.INVALID_BRANCH(branch =
2209 Equation.Branch.BRANCH(condition = cond, conditionVar = var))
2210 guard has_connect
2211 algorithm
2212 ✗ if var <= Variability.STRUCTURAL_PARAMETER then
2213 ✗ Structural.markExp(cond);
2214 ✗ cond := Ceval.evalExp(cond, target);
2215 ✗ cond := flattenExp(cond, prefix, info);
2216 end if;
2217
2218 ✗ if not Expression.isFalse(cond) then
2219 ✗ Equation.Branch.triggerErrors(branch);
2220 end if;
2221 then
2222 bl;
2223
2224 else branch :: bl;
2225 end match;
2226 end while;
2227
2228 // Add the flattened if-equation to the list of equations if there are any
2229 // branches still remaining.
2230
2/2
✓ Branch 0 taken 5724 times.
✓ Branch 1 taken 1488 times.
7212 if not listEmpty(bl) then
2231 1488 equations := Equation.IF(listReverseInPlace(bl), scope, src) :: equations;
2232 end if;
2233 end flattenIfEquation;
2234
2235 function flattenEqBranch
2236 input output Equation.Branch branch;
2237 input Prefix prefix;
2238 input SourceInfo info;
2239 input FlattenSettings settings;
2240 protected
2241 Expression exp;
2242 list<Equation> eql;
2243 Variability var;
2244 algorithm
2245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 367 times.
367 Equation.Branch.BRANCH(exp, var, eql) := branch;
2246 367 exp := flattenExp(exp, prefix, info);
2247 367 eql := flattenEquations(eql, prefix, settings);
2248 367 branch := Equation.makeBranch(exp, listReverseInPlace(eql), var);
2249 end flattenEqBranch;
2250
2251 function unrollForLoop
2252 input Equation forLoop;
2253 input Prefix prefix;
2254 input output list<Equation> equations;
2255 input FlattenSettings settings;
2256 protected
2257 InstNode iter;
2258 list<Equation> body, unrolled_body;
2259 Expression range;
2260 RangeIterator range_iter;
2261 Expression val;
2262 SourceInfo info;
2263 algorithm
2264
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1345 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1345 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1345 times.
1345 Equation.FOR(iterator = iter, range = SOME(range), body = body) := forLoop;
2265 1345 info := Equation.info(forLoop);
2266
2267 // Unroll the loop by replacing the iterator with each of its values in the for loop body.
2268 1345 range := flattenExp(range, prefix, info);
2269 1345 Structural.markExp(range);
2270 1345 range := Ceval.evalExp(range, Ceval.EvalTarget.new(info, NFInstContext.ITERATION_RANGE));
2271 1345 range_iter := RangeIterator.fromExp(range);
2272
2273
2/2
✓ Branch 1 taken 6896 times.
✓ Branch 2 taken 1345 times.
8241 while RangeIterator.hasNext(range_iter) loop
2274 6896 (range_iter, val) := RangeIterator.next(range_iter);
2275 6896 unrolled_body := Equation.replaceIteratorList(body, iter, val);
2276 6896 unrolled_body := flattenEquations(unrolled_body, prefix, settings);
2277 6896 equations := listAppend(unrolled_body, equations);
2278 end while;
2279 end unrollForLoop;
2280
2281 function splitForLoop
2282 input Equation forLoop;
2283 input Prefix prefix;
2284 input output list<Equation> equations;
2285 input FlattenSettings settings;
2286 protected
2287 InstNode iter;
2288 Option<Expression> opt_range;
2289 Expression range;
2290 list<Equation> body, connects, non_connects;
2291 DAE.ElementSource src;
2292 Equation eq;
2293 NFInstNode.ScopeRef scope;
2294 algorithm
2295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 324 times.
324 Equation.FOR(iter, opt_range, body, scope, src) := forLoop;
2296 324 body := flattenEquations(body, EMPTY_PREFIX, settings);
2297 324 (connects, non_connects) := splitForLoop2(body, settings);
2298
2299 // the size parameters in the range like in the dimensions, see resizableDimensionAlias
2300
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 324 times.
✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 282 times.
324 if isSome(opt_range) and Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) then
2301
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 SOME(range) := opt_range;
2302 42 opt_range := SOME(flattenExp(range, EMPTY_PREFIX, ElementSource.getInfo(src)));
2303 end if;
2304
2305
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 289 times.
324 if not listEmpty(connects) then
2306 // with resizable arrays the connections are resolved with symbolic ranges
2307
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 10 times.
35 if isSome(opt_range) and not Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) then
2308
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
25 SOME(range) := opt_range;
2309 25 range := Ceval.evalExp(range, Ceval.EvalTarget.new(Equation.info(forLoop), NFInstContext.ITERATION_RANGE));
2310 25 Structural.markExp(range);
2311 opt_range := SOME(range);
2312 end if;
2313
2314 35 eq := Equation.FOR(iter, opt_range, connects, scope, src);
2315
2316
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 19 times.
35 if settings.arrayConnect then
2317 equations := eq :: equations;
2318 else
2319 19 equations := unrollForLoop(eq, prefix, equations, settings);
2320 end if;
2321 end if;
2322
2323
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 294 times.
324 if not listEmpty(non_connects) then
2324 294 equations := Equation.FOR(iter, opt_range, non_connects, scope, src) :: equations;
2325 end if;
2326 end splitForLoop;
2327
2328 function splitForLoop2
2329 input list<Equation> forBody;
2330 input FlattenSettings settings;
2331 output list<Equation> connects = {};
2332 output list<Equation> nonConnects = {};
2333 protected
2334 list<Equation> conns, nconns;
2335 algorithm
2336
5/5
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 350 times.
✓ Branch 3 taken 425 times.
✓ Branch 4 taken 370 times.
795 for eq in forBody loop
2337 () := match eq
2338 case Equation.CONNECT()
2339 algorithm
2340 connects := eq :: connects;
2341 then
2342 ();
2343
2344 case Equation.FOR()
2345 algorithm
2346 46 (conns, nconns) := splitForLoop2(eq.body, settings);
2347
2348
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 45 times.
46 if not listEmpty(conns) then
2349 1 connects := Equation.FOR(eq.iterator, eq.range, conns, eq.scope, eq.source) :: connects;
2350 end if;
2351
2352
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 1 time.
46 if not listEmpty(nconns) then
2353 45 nonConnects := Equation.FOR(eq.iterator, eq.range, nconns, eq.scope, eq.source) :: nonConnects;
2354 end if;
2355 then
2356 ();
2357
2358 else
2359 algorithm
2360
4/4
✓ Branch 2 taken 349 times.
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 336 times.
350 if Equation.contains(eq, Equation.isConnect) or
2361 Equation.containsExp(eq, function Expression.contains(func = Expression.isConnectionCall)) then
2362 14 connects := eq :: connects;
2363 else
2364 nonConnects := eq :: nonConnects;
2365 end if;
2366 then
2367 ();
2368
2369 end match;
2370 end for;
2371 end splitForLoop2;
2372
2373 function unrollForStatementsInAlg
2374 input output Algorithm alg;
2375 algorithm
2376 ✗ alg.statements := unrollForStatements(alg.statements);
2377 end unrollForStatementsInAlg;
2378
2379 function unrollForStatements
2380 input list<Statement> stmts;
2381 output list<Statement> outStmts = {};
2382 algorithm
2383 ✗ for s in stmts loop
2384 ✗ outStmts := unrollForStatement(s, outStmts);
2385 end for;
2386
2387 ✗ outStmts := listReverseInPlace(outStmts);
2388 end unrollForStatements;
2389
2390 function unrollForStatement
2391 input Statement stmt;
2392 input output list<Statement> statements;
2393 protected
2394 Expression range, val;
2395 SourceInfo info;
2396 RangeIterator range_iter;
2397 list<Statement> stmts;
2398 Boolean has_for;
2399 algorithm
2400 statements := match stmt
2401 case Statement.FOR(range = SOME(range))
2402 algorithm
2403 ✗ info := Statement.info(stmt);
2404
2405 try
2406 ✗ range := Ceval.evalExp(range, Ceval.EvalTarget.new(info, NFInstContext.ITERATION_RANGE));
2407 ✗ range_iter := RangeIterator.fromExp(range);
2408 else
2409 ✗ Error.addSourceMessage(Error.UNROLL_FAILURE, {Statement.toString(stmt)}, info);
2410 ✗ fail();
2411 end try;
2412
2413 ✗ has_for := Statement.containsList(stmt.body, Statement.isFor);
2414
2415 ✗ while RangeIterator.hasNext(range_iter) loop
2416 ✗ (range_iter, val) := RangeIterator.next(range_iter);
2417 ✗ stmts := Statement.replaceIteratorList(stmt.body, stmt.iterator, val);
2418
2419 ✗ if has_for then
2420 // Unroll recursively if there are nested for loops, otherwise skip it to save time.
2421 ✗ stmts := unrollForStatements(stmts);
2422 end if;
2423
2424 ✗ statements := List.append_reverse(stmts, statements);
2425 end while;
2426 ✗ then
2427 statements;
2428
2429 else stmt :: statements;
2430 end match;
2431 end unrollForStatement;
2432
2433 function flattenAlgorithms
2434 input list<Algorithm> algorithms;
2435 input Prefix prefix;
2436 output list<Algorithm> outAlgorithms = {};
2437 algorithm
2438
2/2
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 19480 times.
19678 for alg in algorithms loop
2439 198 alg.statements := flattenStatements(alg.statements, prefix);
2440
2441 // CheckModel relies on the ElementSource to know whether a certain algorithm comes from
2442 // an array component, otherwise is will miscount the number of equations.
2443
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 192 times.
198 if ComponentRef.hasSubscripts(Prefix.prefix(prefix)) then
2444 6 alg.source := addElementSourceArrayPrefix(alg.source, prefix);
2445 end if;
2446
2447 outAlgorithms := alg :: outAlgorithms;
2448 end for;
2449 end flattenAlgorithms;
2450
2451 function flattenStatements
2452 input output list<Statement> stmts;
2453 input Prefix prefix;
2454 algorithm
2455
4/4
✓ Branch 0 taken 980 times.
✓ Branch 1 taken 649 times.
✓ Branch 2 taken 980 times.
✓ Branch 3 taken 649 times.
1629 stmts := list(flattenStatement(s, prefix) for s in stmts);
2456 end flattenStatements;
2457
2458 function flattenStatement
2459 input output Statement stmt;
2460 input Prefix prefix;
2461 protected
2462 SourceInfo info = Statement.info(stmt);
2463 algorithm
2464 stmt := match stmt
2465 local
2466 Expression e1, e2, e3;
2467 Type ty;
2468 list<Statement> body;
2469
2470 case Statement.ASSIGNMENT()
2471 algorithm
2472 544 e1 := flattenExp(stmt.lhs, prefix, info);
2473 544 e2 := flattenExp(stmt.rhs, prefix, info);
2474 544 ty := flattenType(stmt.ty, prefix, info);
2475 544 then
2476 Statement.ASSIGNMENT(e1, e2, ty, stmt.source);
2477
2478 case Statement.FOR()
2479 algorithm
2480 180 stmt.range := Util.applyOption(stmt.range, function flattenExp(prefix = prefix, info = info));
2481 90 stmt.body := flattenStatements(stmt.body, prefix);
2482 90 stmt.forType := updateForType(stmt.forType, stmt.body);
2483 then
2484 stmt;
2485
2486 case Statement.IF()
2487 algorithm
2488
4/4
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 176 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 176 times.
589 stmt.branches := list(flattenStmtBranch(b, prefix, info) for b in stmt.branches);
2489 then
2490 stmt;
2491
2492 case Statement.WHEN()
2493 algorithm
2494
4/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 84 times.
288 stmt.branches := list(flattenStmtBranch(b, prefix, info) for b in stmt.branches);
2495 then
2496 stmt;
2497
2498 case Statement.ASSERT()
2499 algorithm
2500 57 e1 := flattenExp(stmt.condition, prefix, info);
2501 57 e2 := flattenExp(stmt.message, prefix, info);
2502 57 e3 := flattenExp(stmt.level, prefix, info);
2503 57 then
2504 Statement.ASSERT(e1, e2, e3, stmt.source);
2505
2506 case Statement.TERMINATE()
2507 algorithm
2508 1 e1 := flattenExp(stmt.message, prefix, info);
2509 1 then
2510 Statement.TERMINATE(e1, stmt.source);
2511
2512 case Statement.REINIT()
2513 algorithm
2514 4 e1 := flattenExp(stmt.cref, prefix, info);
2515 4 e2 := flattenExp(stmt.reinitExp, prefix, info);
2516 4 then
2517 Statement.REINIT(e1, e2, stmt.source);
2518
2519 case Statement.NORETCALL()
2520 algorithm
2521 24 e1 := flattenExp(stmt.exp, prefix, info);
2522 24 then
2523 Statement.NORETCALL(e1, stmt.source);
2524
2525 case Statement.WHILE()
2526 algorithm
2527 ✗ e1 := flattenExp(stmt.condition, prefix, info);
2528 ✗ body := flattenStatements(stmt.body, prefix);
2529 ✗ then
2530 Statement.WHILE(e1, body, stmt.source);
2531
2532 case Statement.FAILURE()
2533 algorithm
2534 ✗ body := flattenStatements(stmt.body, prefix);
2535 ✗ then
2536 Statement.FAILURE(body, stmt.source);
2537
2538 else stmt;
2539 end match;
2540 end flattenStatement;
2541
2542 function flattenStmtBranch
2543 input output tuple<Expression, list<Statement>> branch;
2544 input Prefix prefix;
2545 input SourceInfo info;
2546 protected
2547 Expression cond;
2548 list<Statement> body;
2549 algorithm
2550 357 (cond, body) := branch;
2551 357 cond := flattenExp(cond, prefix, info);
2552 357 body := flattenStatements(body, prefix);
2553 357 branch := (cond, body);
2554 end flattenStmtBranch;
2555
2556 function addElementSourceArrayPrefix
2557 input output DAE.ElementSource source;
2558 input Prefix prefix;
2559 protected
2560 DAE.ComponentPrefix comp_pre;
2561 algorithm
2562 // It seems the backend doesn't really care about the ComponentPrefix, and
2563 // creating a proper prefix here could be rather expensive. So we just create
2564 // a dummy prefix here with one subscript to keep CheckModel happy.
2565 6 comp_pre := DAE.ComponentPrefix.PRE(
2566 ComponentRef.firstName(Prefix.prefix(prefix)),
2567 {},
2568 {DAE.Subscript.INDEX(DAE.Exp.ICONST(-1))},
2569 DAE.ComponentPrefix.NOCOMPPRE(),
2570 ClassInf.State.UNKNOWN(Absyn.IDENT("?")),
2571 Absyn.dummyInfo
2572 );
2573
2574 6 source := ElementSource.addElementSourceInstanceOpt(source, comp_pre);
2575 end addElementSourceArrayPrefix;
2576
2577 function isDeletedCref
2578 input ComponentRef cref;
2579 input DeletedVariables deletedVars;
2580 output Boolean res;
2581 protected
2582 ComponentRef cr = cref;
2583 InstNode node;
2584 algorithm
2585 591081 cr := ComponentRef.stripSubscripts(cref);
2586
2587
2/2
✓ Branch 1 taken 2017714 times.
✓ Branch 2 taken 589967 times.
2607681 while ComponentRef.isCref(cr) loop
2588 2017714 node := ComponentRef.node(cr);
2589
2590
4/4
✓ Branch 1 taken 1954092 times.
✓ Branch 2 taken 63622 times.
✓ Branch 5 taken 47614 times.
✓ Branch 6 taken 1906478 times.
2017714 if InstNode.isComponent(node) and Component.hasCondition(InstNode.component(node)) then
2591
2/2
✓ Branch 1 taken 1114 times.
✓ Branch 2 taken 46500 times.
47614 if UnorderedSet.contains(cr, deletedVars) then
2592 res := true;
2593 1114 return;
2594 end if;
2595 end if;
2596
2597 2016600 cr := ComponentRef.stripSubscripts(ComponentRef.rest(cr));
2598 end while;
2599
2600 res := false;
2601 end isDeletedCref;
2602
2603 function resolveConnections
2604 "Generates the connect equations and adds them to the equation list"
2605 input output FlatModel flatModel;
2606 input DeletedVariables deletedVars;
2607 input FlattenSettings settings;
2608 protected
2609 Connections conns;
2610 list<Equation> conn_eql, stream_eql, ec_eql, tlio_eql;
2611 list<Variable> tlio_vars;
2612 ConnectionSets.Sets csets;
2613 array<list<Connector>> csets_array;
2614 list<list<Connector>> unhandled_stream_sets;
2615 CardinalityTable.Table ctable;
2616 Connections.BrokenEdges broken = {};
2617 UnorderedMap<ComponentRef, Variable> vars;
2618 UnorderedSet<ComponentRef> connectedLocalIOs;
2619 Integer exposeLocalIOs;
2620 StreamFlowAlias.Replacements flow_alias_repl;
2621 Option<StreamFlowAlias.Replacements> flow_alias_repl_opt = NONE();
2622 algorithm
2623 1571 vars := UnorderedMap.new<Variable>(ComponentRef.hash, ComponentRef.isEqual,
2624 listLength(flatModel.variables));
2625
2626
2/2
✓ Branch 0 taken 240616 times.
✓ Branch 1 taken 1571 times.
242187 for v in flatModel.variables loop
2627 240616 UnorderedMap.addNew(v.name, v, vars);
2628 end for;
2629
2630 // Collect connections from the model.
2631 1571 (flatModel, conns) := Connections.collectConnections(flatModel,
2632 function isDeletedCref(deletedVars = deletedVars));
2633 1571 ctable := CardinalityTable.fromConnections(conns);
2634
2635 // Elaborate expandable connectors.
2636 1571 (flatModel, conns) := ExpandableConnectors.elaborate(flatModel, conns);
2637
6/6
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 240574 times.
✓ Branch 3 taken 240688 times.
✓ Branch 4 taken 1571 times.
✓ Branch 5 taken 240574 times.
✓ Branch 6 taken 1571 times.
243830 flatModel.variables := list(v for v guard Variable.isPresent(v) in flatModel.variables);
2638
2639 // Collect flow variables from the model, which needs to be done after
2640 // elaborating expandable connectors to get all of them.
2641 1571 conns := Connections.collectFlows(flatModel, conns);
2642
2643 // handle overconstrained connections
2644 // - build the graph
2645 // - evaluate the Connections.* operators
2646 // - generate the equations to replace the broken connects
2647 // - return the broken connects + the equations
2648
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 1495 times.
1571 if System.getHasOverconstrainedConnectors() then
2649 76 (flatModel, broken) := NFOCConnectionGraph.handleOverconstrainedConnections(flatModel, conns,
2650 function isDeletedCref(deletedVars = deletedVars));
2651 end if;
2652 // add the broken connections
2653 1571 conns := Connections.addBroken(broken, conns);
2654 // build the sets, check the broken connects
2655 1571 conns := Connections.split(conns);
2656 1571 conns := Connections.scalarize(conns, keepSingleConnectedArrays = not settings.scalarize);
2657
2658 1571 csets := ConnectionSets.fromConnections(conns);
2659 1571 csets_array := ConnectionSets.extractSets(csets);
2660 // generate the equations
2661 1571 (conn_eql, connectedLocalIOs, unhandled_stream_sets) := ConnectEquations.generateEquations(csets_array, vars);
2662
2663 // append the equalityConstraint call equations for the broken connects
2664
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 1495 times.
1571 if System.getHasOverconstrainedConnectors() then
2665
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 76 times.
108 ec_eql := List.flatten(list(e.brokenEquations for e in broken));
2666 76 flatModel.equations := listAppend(ec_eql, flatModel.equations);
2667 end if;
2668
2669 // add the equations to the flat model
2670 1571 flatModel.equations := listAppend(conn_eql, flatModel.equations);
2671
2672 // do flow alias elimination if it's enabled
2673
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1563 times.
1571 if not listEmpty(unhandled_stream_sets) then
2674 8 (flatModel, flow_alias_repl) := StreamFlowAlias.eliminateAliases(flatModel, vars);
2675 7 conn_eql := ConnectEquations.generateStreamEquationsList(unhandled_stream_sets, vars, flow_alias_repl);
2676 7 conn_eql := StreamFlowAlias.applyReplacementsInEql(flow_alias_repl, conn_eql);
2677 7 flatModel.equations := listAppend(conn_eql, flatModel.equations);
2678 7 flow_alias_repl_opt := SOME(flow_alias_repl);
2679 end if;
2680
2681 // add top-level IOs for unconnected local IOs
2682 1570 exposeLocalIOs := Flags.getConfigInt(Flags.EXPOSE_LOCAL_IOS);
2683
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1569 times.
1570 if exposeLocalIOs > 0 then
2684 1 (tlio_vars, tlio_eql) := generateTopLevelIOs(vars, connectedLocalIOs, exposeLocalIOs);
2685 1 flatModel.variables := List.append_reverse(flatModel.variables, tlio_vars);
2686 flatModel.equations := List.append_reverse(flatModel.equations, tlio_eql);
2687 end if;
2688
2689 // Evaluate any connection operators if they're used.
2690
4/4
✓ Branch 1 taken 1397 times.
✓ Branch 2 taken 173 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 1292 times.
1570 if System.getHasStreamConnectors() or System.getUsesCardinality() then
2691 278 flatModel := evaluateConnectionOperators(flatModel, csets, csets_array, vars, ctable, flow_alias_repl_opt);
2692 end if;
2693
2694 // FMI 3.0 flange causalization: expose unconnected acausal connectors as a
2695 // causal FMU boundary (flow -> input, potential -> output) so the FMU can be
2696 // reconnected into a physical circuit (issue #15686). Restricted to the old
2697 // backend: the new backend's initialization (NBResolveSingularities) cannot yet
2698 // balance the model once the zero-flow equations are replaced by boundary inputs.
2699
7/8
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1505 times.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 50 times.
✓ Branch 10 taken 12 times.
✓ Branch 11 taken 3 times.
1570 if Flags.getConfigBool(Flags.BUILDING_FMU) and stringEq(Flags.getConfigString(Flags.FMI_VERSION), "3.0")
2700 and not settings.newBackend then
2701 12 flatModel := causalizeAcausalConnectors(flatModel);
2702 end if;
2703
2704 1570 execStat(getInstanceName());
2705 end resolveConnections;
2706
2707 function generateTopLevelIOs
2708 "generate top-level inputs and outputs for public unconnected local input and output connectors"
2709 input UnorderedMap<ComponentRef, Variable> variables;
2710 input UnorderedSet<ComponentRef> connectedLocalIOs;
2711 input Integer exposeLocalIOs;
2712 output list<Variable> tlio_vars;
2713 output list<Equation> tlio_eql;
2714 protected
2715 Attributes attributes;
2716 Variable tlio_var;
2717 ComponentRef cref;
2718 String name;
2719 InstNode tlio_node;
2720 Integer level;
2721 algorithm
2722 tlio_vars := {};
2723 tlio_eql := {};
2724
2/2
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 1 time.
30 for variable in UnorderedMap.valueList(variables) loop
2725 29 level := ComponentRef.depth(variable.name) - 1;
2726 29 attributes := variable.attributes;
2727
9/10
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 4 times.
29 if 0 < level and level <= exposeLocalIOs and
2728 variable.visibility == Visibility.PUBLIC and
2729 attributes.connectorType <> ConnectorType.NON_CONNECTOR and
2730 (attributes.direction == Direction.INPUT or attributes.direction == Direction.OUTPUT) and
2731 not UnorderedSet.contains(variable.name, connectedLocalIOs)
2732 then
2733 // add a new variable and equation if removeNonTopLevelDirection removes the direction
2734 7 tlio_var := Variable.removeNonTopLevelDirection(variable);
2735 7 attributes := tlio_var.attributes;
2736
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if attributes.direction == Direction.NONE then
2737 tlio_var := variable; // same attributes like start, unit
2738 5 tlio_var.binding := UNBOUND(); // value is defined with tlio_eql
2739 // find new name in global scope, starting with quoted identifier
2740 5 cref := tlio_var.name;
2741 5 name := stringDelimitList(ComponentRef.toString_impl(cref, {}), ".");
2742
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5 times.
11 while UnorderedMap.contains(tlio_var.name, variables) loop
2743 6 tlio_node := InstNode.NAME_NODE(Util.makeQuotedIdentifier(name));
2744 6 tlio_var.name := match cref case ComponentRef.CREF() then
2745 ComponentRef.prefixCref(tlio_node, cref.ty, cref.subscripts, ComponentRef.EMPTY());
2746 end match;
2747 6 name := name + "_" "append underscore until name is unique";
2748 end while;
2749 tlio_vars := tlio_var :: tlio_vars;
2750 5 tlio_eql := Equation.makeCrefEquality(variable.name, tlio_var.name,
2751 InstNode.EMPTY_NODE(), ElementSource.createElementSource(variable.info)) :: tlio_eql;
2752 end if;
2753 end if;
2754 end for;
2755 end generateTopLevelIOs;
2756
2757 function causalizeAcausalConnectors
2758 "FMI 3.0 flange causalization (issue #15686). Turn the model's unconnected
2759 acausal (physical) connectors into a causal FMU boundary so the exported FMU can
2760 be reconnected into a Modelica physical circuit. An unconnected flow variable
2761 normally gets a `flow = 0` equation; instead expose the flow as an input and the
2762 connector's potential variable(s) as outputs (the convention Dymola uses for
2763 FMI terminal export) and drop the zero-flow equation. The backend then
2764 causalizes the model in the natural 'component driven by its boundary flows'
2765 form. Only triggered for FMI 3.0 export."
2766 input output FlatModel flatModel;
2767 protected
2768 list<ComponentRef> flowCrefs;
2769 list<ComponentRef> unconnectedFlows = {};
2770 list<ComponentRef> boundaryConnectors = {};
2771 list<Equation> kept = {};
2772 Boolean isZeroFlowEq;
2773 ComponentRef fc;
2774 algorithm
2775 // crefs of all flow connector members (to tell a generated zero-flow equation
2776 // apart from a genuine `x = 0` model equation). Only public ones: a protected
2777 // connector is an internal wiring node, not an FMU boundary.
2778
8/8
✓ Branch 1 taken 186 times.
✓ Branch 2 taken 1489 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 159 times.
✓ Branch 6 taken 1675 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 159 times.
✓ Branch 9 taken 12 times.
1687 flowCrefs := list(v.name for v guard Variable.isFlow(v) and Variable.isPublic(v) in flatModel.variables);
2779
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if listEmpty(flowCrefs) then return; end if;
2780
2781 // collect and drop the `flow = 0` equations of unconnected flows.
2782 // Only the exported model's OWN top-level connectors form the FMU boundary, so
2783 // restrict to flows whose connector is a direct child of the model root
2784 // (ComponentRef.rest(fc) is simple, e.g. flange_a.tau -> flange_a). Internal
2785 // unconnected sub-connector flows (e.g. cylinder.fixed.flange.f) legitimately
2786 // keep their `flow = 0` equation; causalizing them would drop equations the
2787 // model needs and leave it under-determined (issue #15686).
2788
2/2
✓ Branch 0 taken 1348 times.
✓ Branch 1 taken 4 times.
1352 for eq in flatModel.equations loop
2789 isZeroFlowEq := false;
2790 () := match eq
2791 local Real rv;
2792 case Equation.EQUALITY(lhs = Expression.CREF(cref = fc), rhs = Expression.REAL(value = rv))
2793 guard rv == 0.0 and List.isMemberOnTrue(fc, flowCrefs, ComponentRef.isEqual)
2794 and ComponentRef.isSimple(ComponentRef.rest(fc))
2795 algorithm
2796 unconnectedFlows := fc :: unconnectedFlows;
2797 2 boundaryConnectors := ComponentRef.rest(fc) :: boundaryConnectors;
2798 isZeroFlowEq := true;
2799 then ();
2800 else ();
2801 end match;
2802
2/2
✓ Branch 0 taken 1346 times.
✓ Branch 1 taken 2 times.
1348 if not isZeroFlowEq then
2803 kept := eq :: kept;
2804 end if;
2805 end for;
2806
2807
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if listEmpty(unconnectedFlows) then
2808 3 return;
2809 end if;
2810
2811
4/4
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1 time.
8 flatModel.equations := listReverseInPlace(kept);
2812 flatModel.variables := list(causalizeAcausalVar(v, unconnectedFlows, boundaryConnectors)
2813 for v in flatModel.variables);
2814 end causalizeAcausalConnectors;
2815
2816 function causalizeAcausalVar
2817 "Reclassify a boundary connector member: an unconnected flow becomes an input,
2818 a potential of such a connector becomes an output."
2819 input output Variable var;
2820 input list<ComponentRef> unconnectedFlows;
2821 input list<ComponentRef> boundaryConnectors;
2822 protected
2823 Attributes attr;
2824 algorithm
2825
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
7 if Variable.isFlow(var) and List.isMemberOnTrue(var.name, unconnectedFlows, ComponentRef.isEqual) then
2826 2 attr := var.attributes;
2827 2 attr.direction := Direction.INPUT;
2828 2 var.attributes := attr;
2829 elseif Variable.isPotential(var) and
2830 List.isMemberOnTrue(ComponentRef.rest(var.name), boundaryConnectors, ComponentRef.isEqual) then
2831 2 attr := var.attributes;
2832 2 attr.direction := Direction.OUTPUT;
2833 2 var.attributes := attr;
2834 end if;
2835 end causalizeAcausalVar;
2836
2837 function evaluateConnectionOperators
2838 input output FlatModel flatModel;
2839 input ConnectionSets.Sets sets;
2840 input array<list<Connector>> setsArray;
2841 input UnorderedMap<ComponentRef, Variable> variables;
2842 input CardinalityTable.Table ctable;
2843 input Option<StreamFlowAlias.Replacements> replacements;
2844 algorithm
2845
4/4
✓ Branch 0 taken 100141 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 100141 times.
✓ Branch 3 taken 278 times.
100419 flatModel.variables := list(evaluateBindingConnOp(c, sets, setsArray, variables, ctable, replacements) for c in flatModel.variables);
2846 flatModel.equations := evaluateEquationsConnOp(flatModel.equations, sets, setsArray, variables, ctable, replacements);
2847 flatModel.initialEquations := evaluateEquationsConnOp(flatModel.initialEquations, sets, setsArray, variables, ctable, replacements);
2848 flatModel.algorithms := evaluateAlgorithmsConnOp(flatModel.algorithms, sets, setsArray, variables, ctable, replacements);
2849 flatModel.initialAlgorithms := evaluateAlgorithmsConnOp(flatModel.initialAlgorithms, sets, setsArray, variables, ctable, replacements);
2850 end evaluateConnectionOperators;
2851
2852 function evaluateAlgorithmsConnOp
2853 input output list<Algorithm> algorithms;
2854 input ConnectionSets.Sets sets;
2855 input array<list<Connector>> setsArray;
2856 input UnorderedMap<ComponentRef, Variable> variables;
2857 input CardinalityTable.Table ctable;
2858 input Option<StreamFlowAlias.Replacements> replacements;
2859 algorithm
2860 556 algorithms := Algorithm.mapExpList(algorithms,
2861 function ConnectEquations.evaluateOperators(sets = sets, setsArray = setsArray,
2862 variables = variables, ctable = ctable, replacements = replacements));
2863 end evaluateAlgorithmsConnOp;
2864
2865 function evaluateBindingConnOp
2866 input output Variable var;
2867 input ConnectionSets.Sets sets;
2868 input array<list<Connector>> setsArray;
2869 input UnorderedMap<ComponentRef, Variable> variables;
2870 input CardinalityTable.Table ctable;
2871 input Option<StreamFlowAlias.Replacements> replacements;
2872 protected
2873 Expression exp, eval_exp;
2874 algorithm
2875 () := match var
2876 case Variable.VARIABLE()
2877 guard Binding.hasExp(var.binding)
2878 algorithm
2879 44937 exp := Binding.getExp(var.binding);
2880 44937 eval_exp := ConnectEquations.evaluateOperators(exp, sets, setsArray, variables, ctable, replacements);
2881
2882
2/2
✓ Branch 0 taken 23852 times.
✓ Branch 1 taken 21085 times.
44937 if not referenceEq(exp, eval_exp) then
2883 23852 var.binding := Binding.setExp(eval_exp, var.binding);
2884 end if;
2885 then
2886 ();
2887
2888 else ();
2889 end match;
2890 end evaluateBindingConnOp;
2891
2892 function evaluateEquationsConnOp
2893 input output list<Equation> equations;
2894 input ConnectionSets.Sets sets;
2895 input array<list<Connector>> setsArray;
2896 input UnorderedMap<ComponentRef, Variable> variables;
2897 input CardinalityTable.Table ctable;
2898 input Option<StreamFlowAlias.Replacements> replacements;
2899 algorithm
2900
4/4
✓ Branch 0 taken 85403 times.
✓ Branch 1 taken 556 times.
✓ Branch 2 taken 85403 times.
✓ Branch 3 taken 556 times.
85959 equations := list(evaluateEquationConnOp(eq, sets, setsArray, variables, ctable, replacements) for eq in equations);
2901 end evaluateEquationsConnOp;
2902
2903 function evaluateEquationConnOp
2904 input output Equation eq;
2905 input ConnectionSets.Sets sets;
2906 input array<list<Connector>> setsArray;
2907 input UnorderedMap<ComponentRef, Variable> variables;
2908 input CardinalityTable.Table ctable;
2909 input Option<StreamFlowAlias.Replacements> replacements;
2910 algorithm
2911 85403 eq := Equation.mapExp(eq,
2912 function ConnectEquations.evaluateOperators(sets = sets, setsArray = setsArray,
2913 variables = variables, ctable = ctable, replacements = replacements));
2914
2915 () := match eq
2916 case Equation.IF()
2917 algorithm
2918
2/2
✓ Branch 0 taken 1776 times.
✓ Branch 1 taken 966 times.
2742 for b in eq.branches loop
2919 () := match b
2920 case Equation.Branch.BRANCH()
2921 algorithm
2922
3/4
✓ Branch 0 taken 859 times.
✓ Branch 1 taken 917 times.
✓ Branch 3 taken 859 times.
✗ Branch 4 not taken.
1776 if b.conditionVar == Variability.PARAMETER and not
2923 Structural.isExpressionNotFixed(b.condition, maxDepth = 100)
2924 then
2925 859 Structural.markExp(b.condition);
2926 end if;
2927 then
2928 ();
2929
2930 else ();
2931 end match;
2932 end for;
2933 then
2934 ();
2935
2936 else ();
2937 end match;
2938 end evaluateEquationConnOp;
2939
2940 function resolveArrayConnections
2941 "Generates the connect equations and adds them to the equation list"
2942 input output FlatModel flatModel;
2943 input DeletedVariables deletedVars;
2944 protected
2945 Connections conns;
2946 Connections.BrokenEdges broken;
2947 FlatModel unrolled;
2948 Boolean symbolic_oc;
2949 algorithm
2950 // the array handlers do not know about deleted conditional components
2951 15 flatModel.equations := removeDeletedConnects(flatModel.equations, deletedVars);
2952
2953 // Overconstrained connections: build the graph like resolveConnections, which
2954 // evaluates the Connections.* operators (isRoot, rooted). The connect equations
2955 // stay in the model for the array handler.
2956 // with resizable arrays the graph is built with symbolic sizes if possible
2957 15 symbolic_oc := false;
2958
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
15 if System.getHasOverconstrainedConnectors() and Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) then
2959 ✗ (flatModel, symbolic_oc) := ResizableConnections.resolveOverconstrained(flatModel);
2960 end if;
2961
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
15 if System.getHasOverconstrainedConnectors() and not symbolic_oc then
2962 // the graph needs the single connections, roots and branches: unroll the
2963 // for loops of a copy of the equations for it
2964 ✗ unrolled := FlatModel.FLAT_MODEL(flatModel.name, {}, unrollForGraph(flatModel.equations), {}, {}, {}, flatModel.source);
2965 ✗ (_, conns) := Connections.collectConnections(unrolled, function isDeletedCref(deletedVars = deletedVars));
2966 ✗ (flatModel, broken) := NFOCConnectionGraph.handleOverconstrainedArrayConnections(flatModel, unrolled.equations, conns,
2967 function isDeletedCref(deletedVars = deletedVars));
2968 ✗ if not listEmpty(broken) then
2969 ✗ Error.addInternalError(getInstanceName() + ": overconstrained connection graphs with loops (broken connections) are not supported with array connections yet.", sourceInfo());
2970 ✗ fail();
2971 end if;
2972 end if;
2973
2974
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 3 times.
15 if Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) then
2975 // sizes, ranges and indices stay symbolic in the size parameters
2976 12 flatModel := ResizableConnections.resolve(flatModel);
2977 else
2978 3 flatModel := ArrayConnections.resolve(flatModel);
2979 end if;
2980 15 execStat(getInstanceName());
2981 end resolveArrayConnections;
2982
2983 function removeDeletedConnects
2984 "Removes the connect equations with a deleted conditional connector, also
2985 inside for loops."
2986 input list<Equation> equations;
2987 input DeletedVariables deletedVars;
2988 output list<Equation> outEquations = {};
2989 protected
2990 list<Equation> body;
2991 algorithm
2992
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 71 times.
232 for eq in equations loop
2993 outEquations := match eq
2994 case Equation.CONNECT()
2995 guard isDeletedConnector(eq.lhs, deletedVars) or isDeletedConnector(eq.rhs, deletedVars)
2996 then outEquations;
2997 case Equation.FOR() algorithm
2998 56 body := removeDeletedConnects(eq.body, deletedVars);
2999
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 then if listEmpty(body) then outEquations else Equation.FOR(eq.iterator, eq.range, body, eq.scope, eq.source) :: outEquations;
3000 else eq :: outEquations;
3001 end match;
3002 end for;
3003 71 outEquations := listReverseInPlace(outEquations);
3004 end removeDeletedConnects;
3005
3006 function isDeletedConnector
3007 input Expression exp;
3008 input DeletedVariables deletedVars;
3009 output Boolean res;
3010 algorithm
3011 res := match exp
3012 82 case Expression.CREF() then isDeletedCref(exp.cref, deletedVars);
3013 else false;
3014 end match;
3015 end isDeletedConnector;
3016
3017 function unrollForGraph
3018 "The equations with their for loops unrolled, the ranges evaluated. Only for
3019 building the overconstrained connection graph, the model keeps the loops."
3020 input list<Equation> equations;
3021 output list<Equation> outEquations = {};
3022 protected
3023 Expression range, val;
3024 RangeIterator range_iter;
3025 algorithm
3026 ✗ for eq in equations loop
3027 outEquations := match eq
3028 case Equation.FOR(range = SOME(range)) algorithm
3029 ✗ range := Ceval.evalExp(range, Ceval.EvalTarget.new(Equation.info(eq), NFInstContext.ITERATION_RANGE));
3030 ✗ range_iter := RangeIterator.fromExp(range);
3031 ✗ while RangeIterator.hasNext(range_iter) loop
3032 ✗ (range_iter, val) := RangeIterator.next(range_iter);
3033 ✗ outEquations := List.append_reverse(unrollForGraph(Equation.replaceIteratorList(eq.body, eq.iterator, val)), outEquations);
3034 end while;
3035 then outEquations;
3036 else eq :: outEquations;
3037 end match;
3038 end for;
3039 ✗ outEquations := listReverseInPlace(outEquations);
3040 end unrollForGraph;
3041
3042 function collectComponentFuncs
3043 input Variable var;
3044 input output FunctionTree funcs;
3045 algorithm
3046 () := match var
3047 case Variable.VARIABLE()
3048 algorithm
3049 241287 funcs := collectTypeFuncs(var.ty, funcs);
3050 241287 funcs := collectBindingFuncs(var.binding, funcs);
3051
3052
2/2
✓ Branch 0 taken 472125 times.
✓ Branch 1 taken 241287 times.
713412 for attr in var.typeAttributes loop
3053 472125 funcs := collectBindingFuncs(Util.tuple22(attr), funcs);
3054 end for;
3055
3056
2/2
✓ Branch 0 taken 445 times.
✓ Branch 1 taken 241287 times.
241732 for c in var.children loop
3057 445 funcs := collectComponentFuncs(c, funcs);
3058 end for;
3059 then
3060 ();
3061
3062 end match;
3063 end collectComponentFuncs;
3064
3065 function collectBindingFuncs
3066 input Binding binding;
3067 input output FunctionTree funcs;
3068 algorithm
3069
2/2
✓ Branch 1 taken 110083 times.
✓ Branch 2 taken 603329 times.
713412 if Binding.isExplicitlyBound(binding) then
3070 603329 funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
3071 end if;
3072 end collectBindingFuncs;
3073
3074 function collectTypeFuncs
3075 input Type ty;
3076 input output FunctionTree funcs;
3077 protected
3078 algorithm
3079 () := match ty
3080 local
3081 NFInstNode.ScopeRef con, de;
3082 NFInstNode.ScopeRef rec_con;
3083 Function fn;
3084
3085 case Type.ARRAY()
3086 algorithm
3087 135524 funcs := Dimension.foldExpList(ty.dimensions, collectExpFuncs_traverse, funcs);
3088 135524 funcs := collectTypeFuncs(ty.elementType, funcs);
3089 then
3090 ();
3091
3092 case Type.FUNCTION(fn = fn)
3093 algorithm
3094 38 funcs := flattenFunction(fn, funcs);
3095 then
3096 ();
3097
3098 // Collect external object structors.
3099 case Type.COMPLEX(complexTy = ComplexType.EXTERNAL_OBJECT(constructor = con, destructor = de))
3100 algorithm
3101 582 funcs := collectStructor(InstNode.borrow(con), funcs);
3102 582 funcs := collectStructor(InstNode.borrow(de), funcs);
3103 then
3104 ();
3105
3106 // Collect record constructors.
3107 case Type.COMPLEX(complexTy = ComplexType.RECORD(constructor = rec_con))
3108 algorithm
3109 34922 funcs := collectStructor(InstNode.borrow(rec_con), funcs);
3110 then
3111 ();
3112
3113 else ();
3114 end match;
3115 end collectTypeFuncs;
3116
3117 function collectStructor
3118 input InstNode node;
3119 input output FunctionTree funcs;
3120 protected
3121 CachedData cache;
3122 list<Function> fn;
3123 algorithm
3124 36086 cache := InstNode.getFuncCache(node);
3125
3126 () := match cache
3127 case CachedData.FUNCTION()
3128 algorithm
3129
2/2
✓ Branch 0 taken 43321 times.
✓ Branch 1 taken 36086 times.
79407 for fn in cache.funcs loop
3130 43321 funcs := flattenFunction(fn, funcs);
3131 end for;
3132 then
3133 ();
3134
3135 else ();
3136 end match;
3137 end collectStructor;
3138
3139 function collectEquationFuncs
3140 input Equation eq;
3141 input output FunctionTree funcs;
3142 algorithm
3143 () := match eq
3144 case Equation.EQUALITY()
3145 algorithm
3146 136086 funcs := collectExpFuncs(eq.lhs, funcs);
3147 136086 funcs := collectExpFuncs(eq.rhs, funcs);
3148 136086 funcs := collectTypeFuncs(eq.ty, funcs);
3149 then
3150 ();
3151
3152 // For equations are always unrolled, so functions in the range doesn't
3153 // matter since they are always evaluated.
3154 case Equation.FOR()
3155 algorithm
3156 292 funcs := List.fold(eq.body, collectEquationFuncs, funcs);
3157 then
3158 ();
3159
3160 case Equation.IF()
3161 algorithm
3162 183 funcs := List.fold(eq.branches, collectEqBranchFuncs, funcs);
3163 then
3164 ();
3165
3166 case Equation.WHEN()
3167 algorithm
3168 320 funcs := List.fold(eq.branches, collectEqBranchFuncs, funcs);
3169 then
3170 ();
3171
3172 case Equation.ASSERT()
3173 algorithm
3174 2011 funcs := collectExpFuncs(eq.condition, funcs);
3175 2011 funcs := collectExpFuncs(eq.message, funcs);
3176 2011 funcs := collectExpFuncs(eq.level, funcs);
3177 then
3178 ();
3179
3180 case Equation.TERMINATE()
3181 algorithm
3182 5 funcs := collectExpFuncs(eq.message, funcs);
3183 then
3184 ();
3185
3186 case Equation.REINIT()
3187 algorithm
3188 28 funcs := collectExpFuncs(eq.reinitExp, funcs);
3189 then
3190 ();
3191
3192 case Equation.NORETCALL()
3193 algorithm
3194 58 funcs := collectExpFuncs(eq.exp, funcs);
3195 then
3196 ();
3197
3198 else ();
3199 end match;
3200 end collectEquationFuncs;
3201
3202 function collectEqBranchFuncs
3203 input Equation.Branch branch;
3204 input output FunctionTree funcs;
3205 algorithm
3206 () := match branch
3207 case Equation.Branch.BRANCH()
3208 algorithm
3209 983 funcs := collectExpFuncs(branch.condition, funcs);
3210 983 funcs := List.fold(branch.body, collectEquationFuncs, funcs);
3211 then
3212 ();
3213
3214 else ();
3215 end match;
3216 end collectEqBranchFuncs;
3217
3218 function collectAlgorithmFuncs
3219 input Algorithm alg;
3220 input output FunctionTree funcs;
3221 algorithm
3222 9672 funcs := List.fold(alg.statements, collectStatementFuncs, funcs);
3223 end collectAlgorithmFuncs;
3224
3225 function collectStatementFuncs
3226 input Statement stmt;
3227 input output FunctionTree funcs;
3228 algorithm
3229 () := match stmt
3230 case Statement.ASSIGNMENT()
3231 algorithm
3232 86062 funcs := collectExpFuncs(stmt.lhs, funcs);
3233 86062 funcs := collectExpFuncs(stmt.rhs, funcs);
3234 86062 funcs := collectTypeFuncs(stmt.ty, funcs);
3235 then
3236 ();
3237
3238 case Statement.FOR()
3239 algorithm
3240 450 funcs := List.fold(stmt.body, collectStatementFuncs, funcs);
3241 450 funcs := collectExpFuncs(Util.getOption(stmt.range), funcs);
3242 then
3243 ();
3244
3245 case Statement.IF()
3246 algorithm
3247 4525 funcs := List.fold(stmt.branches, collectStmtBranchFuncs, funcs);
3248 then
3249 ();
3250
3251 case Statement.WHEN()
3252 algorithm
3253 82 funcs := List.fold(stmt.branches, collectStmtBranchFuncs, funcs);
3254 then
3255 ();
3256
3257 case Statement.ASSERT()
3258 algorithm
3259 2120 funcs := collectExpFuncs(stmt.condition, funcs);
3260 2120 funcs := collectExpFuncs(stmt.message, funcs);
3261 2120 funcs := collectExpFuncs(stmt.level, funcs);
3262 then
3263 ();
3264
3265 case Statement.TERMINATE()
3266 algorithm
3267 1 funcs := collectExpFuncs(stmt.message, funcs);
3268 then
3269 ();
3270
3271 case Statement.REINIT()
3272 algorithm
3273 4 funcs := collectExpFuncs(stmt.cref, funcs);
3274 4 funcs := collectExpFuncs(stmt.reinitExp, funcs);
3275 then
3276 ();
3277
3278 case Statement.NORETCALL()
3279 algorithm
3280 97 funcs := collectExpFuncs(stmt.exp, funcs);
3281 then
3282 ();
3283
3284 case Statement.WHILE()
3285 algorithm
3286 206 funcs := collectExpFuncs(stmt.condition, funcs);
3287 206 funcs := List.fold(stmt.body, collectStatementFuncs, funcs);
3288 then
3289 ();
3290
3291 else ();
3292 end match;
3293 end collectStatementFuncs;
3294
3295 function collectStmtBranchFuncs
3296 input tuple<Expression, list<Statement>> branch;
3297 input output FunctionTree funcs;
3298 algorithm
3299 9681 funcs := collectExpFuncs(Util.tuple21(branch), funcs);
3300 9681 funcs := List.fold(Util.tuple22(branch), collectStatementFuncs, funcs);
3301 end collectStmtBranchFuncs;
3302
3303 function collectExpFuncs
3304 input Expression exp;
3305 input output FunctionTree funcs;
3306 algorithm
3307 1083858 funcs := Expression.fold(exp, collectExpFuncs_traverse, funcs);
3308 end collectExpFuncs;
3309
3310 function collectExpFuncs_traverse
3311 input Expression exp;
3312 input output FunctionTree funcs;
3313 algorithm
3314 () := match exp
3315 local
3316 Function fn;
3317
3318 case Expression.CALL()
3319 algorithm
3320 67211 funcs := flattenFunction(Call.typedFunction(exp.call), funcs);
3321 then
3322 ();
3323
3324 case Expression.CREF()
3325 algorithm
3326 1023978 funcs := collectTypeFuncs(exp.ty, funcs);
3327 then
3328 ();
3329
3330 case Expression.RECORD()
3331 algorithm
3332 2483 funcs := collectTypeFuncs(exp.ty, funcs);
3333 then
3334 ();
3335
3336 case Expression.PARTIAL_FUNCTION_APPLICATION()
3337 algorithm
3338
2/2
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 23 times.
46 for f in Function.getRefCache(exp.fn) loop
3339 23 funcs := flattenFunction(f, funcs);
3340 end for;
3341 then
3342 ();
3343
3344 else ();
3345 end match;
3346 end collectExpFuncs_traverse;
3347
3348 function flattenFunction
3349 input Function func;
3350 input output FunctionTree funcs;
3351 protected
3352 Function fn = func;
3353 algorithm
3354
2/2
✓ Branch 1 taken 99968 times.
✓ Branch 2 taken 11385 times.
111353 if not Function.isCollected(fn) then
3355 11385 fn := Function.mapExp(fn, Expression.expandSplitIndices);
3356 11385 fn := EvalConstants.evaluateFunction(fn);
3357 11385 SimplifyModel.simplifyFunction(fn);
3358
3359
3/4
✓ Branch 1 taken 11385 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10338 times.
✓ Branch 5 taken 1047 times.
11385 if not (Flags.isSet(Flags.NF_API) or Flags.getConfigBool(Flags.CHECK_MODEL)) then
3360 10338 Function.checkUseBeforeAssign(fn);
3361 end if;
3362
3363 11385 Function.collect(fn);
3364
3365
2/2
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 11361 times.
11385 if not InstNode.isPartial(InstNode.fromHandle(fn.node)) then
3366 11361 funcs := FunctionTree.add(funcs, Function.name(fn), fn);
3367 11361 funcs := collectClassFunctions(InstNode.fromHandle(fn.node), funcs);
3368
3369
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 11361 times.
12121 for fn_der in fn.derivatives loop
3370
2/2
✓ Branch 2 taken 760 times.
✓ Branch 3 taken 760 times.
1520 for der_fn in Function.getCachedFuncs(InstNode.borrow(fn_der.derivativeFn)) loop
3371 760 funcs := flattenFunction(der_fn, funcs);
3372 end for;
3373 end for;
3374
3375
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11361 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 11361 times.
22767 for fn_inv in fn.inverses loop
3376 45 funcs := collectExpFuncs(fn_inv.inverseCall, funcs);
3377 end for;
3378
3379
2/2
✓ Branch 1 taken 11360 times.
✓ Branch 2 taken 1 time.
11361 if Function.isPartialDerivative(fn) then
3380
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 for f in Function.getCachedFuncs(Class.lastBaseClass(InstNode.fromHandle(fn.node))) loop
3381 ✗ flattenFunction(f, funcs);
3382 end for;
3383 end if;
3384 end if;
3385 end if;
3386 end flattenFunction;
3387
3388 function collectClassFunctions
3389 input InstNode clsNode;
3390 input output FunctionTree funcs;
3391 protected
3392 Class cls;
3393 ClassTree cls_tree;
3394 Sections sections;
3395 Component comp;
3396 Binding binding;
3397 algorithm
3398 11362 cls := InstNode.getClass(clsNode);
3399
3400 () := match cls
3401 case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE(), sections = sections)
3402 algorithm
3403
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11361 times.
✓ Branch 3 taken 72072 times.
✓ Branch 4 taken 11361 times.
94794 for c in cls_tree.components loop
3404 72072 comp := InstNode.component(c);
3405 72072 funcs := collectTypeFuncs(Component.getType(comp), funcs);
3406 72072 binding := Component.getBinding(comp);
3407
3408
2/2
✓ Branch 1 taken 12278 times.
✓ Branch 2 taken 59794 times.
72072 if Binding.isExplicitlyBound(binding) then
3409 12278 funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
3410 end if;
3411 end for;
3412
3413 () := match sections
3414 case Sections.SECTIONS()
3415 algorithm
3416 9476 funcs := List.fold(sections.algorithms, collectAlgorithmFuncs, funcs);
3417 then
3418 ();
3419
3420 else ();
3421 end match;
3422 then
3423 ();
3424
3425 case Class.TYPED_DERIVED()
3426 algorithm
3427 1 funcs := collectClassFunctions(cls.baseClass, funcs);
3428 then
3429 ();
3430
3431 else ();
3432 end match;
3433 end collectClassFunctions;
3434
3435 function updateForType
3436 input output Statement.ForType forType;
3437 input list<Statement> forBody;
3438 protected
3439 UnorderedMap<ComponentRef, SourceInfo> vars;
3440 algorithm
3441 () := match forType
3442 case Statement.ForType.NORMAL() then ();
3443
3444 case Statement.ForType.PARALLEL()
3445 algorithm
3446 // ParModelica needs to know which variables are used in the loop body,
3447 // so collect them here and add them to the ForType.
3448 ✗ vars := UnorderedMap.new<SourceInfo>(ComponentRef.hash, ComponentRef.isEqual);
3449
3450 ✗ for s in forBody loop
3451 ✗ vars := Statement.fold(s, collectParallelVariables, vars);
3452 end for;
3453
3454 ✗ forType.vars := UnorderedMap.toList(vars);
3455
3456 // Only parglobal variables are allowed to be used in a parfor loop.
3457 ✗ for v in forType.vars loop
3458 ✗ checkParGlobalCref(v);
3459 end for;
3460 then
3461 ();
3462
3463 end match;
3464 end updateForType;
3465
3466 function collectParallelVariables
3467 input Statement stmt;
3468 input output UnorderedMap<ComponentRef, SourceInfo> vars;
3469 protected
3470 SourceInfo info;
3471 algorithm
3472 ✗ info := Statement.info(stmt);
3473 ✗ vars := Statement.foldExp(stmt,
3474 function Expression.fold(func = function collectParallelVariablesExp(info = info)), vars);
3475 end collectParallelVariables;
3476
3477 function collectParallelVariablesExp
3478 input Expression exp;
3479 input SourceInfo info;
3480 input output UnorderedMap<ComponentRef, SourceInfo> vars;
3481 protected
3482 InstNode node;
3483 ComponentRef cref;
3484 algorithm
3485 () := match exp
3486 case Expression.CREF()
3487 guard ComponentRef.isCref(exp.cref) and
3488 not ComponentRef.isIterator(exp.cref) and
3489 InstNode.isComponent(ComponentRef.node(exp.cref))
3490 algorithm
3491 ✗ cref := ComponentRef.stripSubscriptsAll(exp.cref);
3492 ✗ UnorderedMap.tryAdd(cref, info, vars);
3493 then
3494 ();
3495
3496 else ();
3497 end match;
3498 end collectParallelVariablesExp;
3499
3500 function checkParGlobalCref
3501 input tuple<ComponentRef, SourceInfo> crefInfo;
3502 protected
3503 ComponentRef cref;
3504 SourceInfo info;
3505 InstNode node;
3506 String errorString;
3507 algorithm
3508 ✗ (cref, info) := crefInfo;
3509 ✗ node := ComponentRef.node(cref);
3510
3511 ✗ if Component.parallelism(InstNode.component(node)) <> Parallelism.GLOBAL then
3512 ✗ errorString := "\n" +
3513 "- Component '" + AbsynUtil.pathString(ComponentRef.toPath(cref)) +
3514 "' is used in a parallel for loop." + "\n" +
3515 "- Parallel for loops can only contain references to parglobal variables"
3516 ;
3517 ✗ Error.addSourceMessage(Error.PARMODELICA_ERROR,
3518 {errorString}, info);
3519 ✗ fail();
3520 end if;
3521 end checkParGlobalCref;
3522
3523 function verifyDimensions
3524 input list<Dimension> dimensions;
3525 input InstNode component;
3526 algorithm
3527
2/2
✓ Branch 0 taken 59476 times.
✓ Branch 1 taken 243242 times.
302718 for d in dimensions loop
3528 59476 verifyDimension(d, component);
3529 end for;
3530 end verifyDimensions;
3531
3532 function verifyDimension
3533 input Dimension dimension;
3534 input InstNode component;
3535 algorithm
3536 () := match dimension
3537 case Dimension.INTEGER()
3538 algorithm
3539 // Check that integer dimensions are not negative.
3540
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 59435 times.
59436 if dimension.size < 0 then
3541 2 Error.addSourceMessage(Error.NEGATIVE_DIMENSION_INDEX,
3542 {String(dimension.size), InstNode.name(component)}, InstNode.info(component));
3543 1 fail();
3544 end if;
3545 then
3546 ();
3547
3548 else ();
3549 end match;
3550 end verifyDimension;
3551
3552 function updateVariability
3553 input output Variable var;
3554 protected
3555 Variability v;
3556 algorithm
3557
2/2
✓ Branch 0 taken 168479 times.
✓ Branch 1 taken 72258 times.
240737 if var.attributes.variability == Variability.PARAMETER then
3558 72258 v := Component.variability(InstNode.component(ComponentRef.node(var.name)));
3559
3560
2/2
✓ Branch 0 taken 71091 times.
✓ Branch 1 taken 1167 times.
72258 if v < Variability.PARAMETER then
3561 1167 var := Variable.setVariability(var, v);
3562 end if;
3563 end if;
3564 end updateVariability;
3565
3566 function evaluateIfWithConnects
3567 input list<Equation> eql;
3568 output list<Equation> outEql = {};
3569 algorithm
3570
2/2
✓ Branch 0 taken 3670 times.
✓ Branch 1 taken 219 times.
3889 for eq in eql loop
3571 3670 outEql := evaluateIfWithConnects2(eq, outEql);
3572 end for;
3573
3574 219 outEql := listReverseInPlace(outEql);
3575 end evaluateIfWithConnects;
3576
3577 function evaluateIfWithConnects2
3578 input Equation eq;
3579 input output list<Equation> equations;
3580 protected
3581 Expression cond;
3582 Variability var;
3583 list<Equation> eql;
3584 Ceval.EvalTarget target;
3585 list<Equation.Branch> bl = {};
3586 algorithm
3587 equations := match eq
3588 case Equation.IF()
3589 guard Equation.contains(eq, Equation.isConnect) or
3590 Equation.containsExp(eq, function Expression.contains(func = Expression.isConnectionCall))
3591 algorithm
3592 22 target := Ceval.EvalTarget.new(Equation.info(eq));
3593
3594
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1 time.
40 for branch in eq.branches loop
3595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 Equation.Branch.BRANCH(cond, var, eql) := branch;
3596
3597
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 6 times.
39 if var <= Variability.STRUCTURAL_PARAMETER then
3598
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 if Expression.isPure(cond) then
3599 33 Structural.markExp(cond);
3600 33 cond := Ceval.evalExp(cond, target);
3601 end if;
3602
3603
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
33 if not Expression.isBoolean(cond) then
3604 ✗ Error.addInternalError(
3605 "Failed to evaluate branch condition in if equation containing connect equations: `" +
3606 Expression.toString(cond) + "`", Equation.info(eq));
3607 ✗ fail();
3608 end if;
3609 end if;
3610
3611
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 18 times.
39 if Expression.isTrue(cond) then
3612
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 5 times.
21 if listEmpty(bl) then
3613 16 eql := evaluateIfWithConnects(eql);
3614 16 equations := listAppend(eql, equations);
3615 bl := {};
3616 else
3617 5 bl := Equation.makeBranch(cond, eql, var) :: bl;
3618 end if;
3619
3620 break;
3621 elseif not Expression.isFalse(cond) then
3622 6 bl := Equation.makeBranch(cond, eql, var) :: bl;
3623 end if;
3624 end for;
3625
3626
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 if not listEmpty(bl) then
3627 6 equations := Equation.IF(listReverseInPlace(bl), eq.scope, eq.source) :: equations;
3628 end if;
3629 then
3630 equations;
3631
3632 else eq :: equations;
3633 end match;
3634 end evaluateIfWithConnects2;
3635
3636 function checkDeletedVarRefs
3637 input FlatModel flatModel;
3638 input DeletedVariables deletedVars;
3639 input FlattenSettings settings;
3640 algorithm
3641
2/2
✓ Branch 0 taken 240737 times.
✓ Branch 1 taken 1587 times.
242324 for var in flatModel.variables loop
3642 240737 checkDeletedVarRefsInVar(var, deletedVars, settings);
3643 end for;
3644
3645
2/2
✓ Branch 0 taken 138508 times.
✓ Branch 1 taken 1586 times.
140094 for eq in flatModel.equations loop
3646 138508 checkDeletedVarRefsInEq(eq, deletedVars, settings);
3647 end for;
3648
3649
2/2
✓ Branch 0 taken 1686 times.
✓ Branch 1 taken 1586 times.
3272 for eq in flatModel.initialEquations loop
3650 1686 checkDeletedVarRefsInEq(eq, deletedVars, settings);
3651 end for;
3652
3653
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 1585 times.
1731 for alg in flatModel.algorithms loop
3654 146 checkDeletedVarRefsInAlg(alg, deletedVars, settings);
3655 end for;
3656
3657
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 1585 times.
1637 for alg in flatModel.initialAlgorithms loop
3658 52 checkDeletedVarRefsInAlg(alg, deletedVars, settings);
3659 end for;
3660 end checkDeletedVarRefs;
3661
3662 function checkDeletedVarRefsInVar
3663 input Variable var;
3664 input DeletedVariables deletedVars;
3665 input FlattenSettings settings;
3666 algorithm
3667 240737 Variable.applyExpShallow(var,
3668 function checkDeletedVarRefsInExp(deletedVars = deletedVars, settings = settings, info = var.info));
3669 end checkDeletedVarRefsInVar;
3670
3671 function checkDeletedVarRefsInExp
3672 input Expression exp;
3673 input DeletedVariables deletedVars;
3674 input FlattenSettings settings;
3675 input SourceInfo info;
3676 algorithm
3677 903096 Expression.apply(exp,
3678 function checkDeletedVarRefsInExp_traverser(deletedVars = deletedVars, settings = settings, info = info));
3679 end checkDeletedVarRefsInExp;
3680
3681 function checkDeletedVarRefsInExp_traverser
3682 input Expression exp;
3683 input DeletedVariables deletedVars;
3684 input FlattenSettings settings;
3685 input SourceInfo info;
3686 algorithm
3687 () := match exp
3688 case Expression.CREF()
3689 guard isDeletedCref(exp.cref, deletedVars)
3690 algorithm
3691 4 Error.addSourceMessage(Error.INVALID_DELETED_COMPONENT_CONTEXT,
3692 {ComponentRef.toString(exp.cref)}, info);
3693
3694
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if not settings.relaxedErrorChecking then
3695 2 fail();
3696 end if;
3697 then
3698 ();
3699
3700 else ();
3701 end match;
3702 end checkDeletedVarRefsInExp_traverser;
3703
3704 function checkDeletedVarRefsInEq
3705 input Equation eq;
3706 input DeletedVariables deletedVars;
3707 input FlattenSettings settings;
3708 algorithm
3709 140194 Equation.applyExp(eq,
3710 function checkDeletedVarRefsInExp(deletedVars = deletedVars, settings = settings, info = Equation.info(eq)));
3711 end checkDeletedVarRefsInEq;
3712
3713 function checkDeletedVarRefsInAlg
3714 input Algorithm alg;
3715 input DeletedVariables deletedVars;
3716 input FlattenSettings settings;
3717 algorithm
3718
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 197 times.
628 for stmt in alg.statements loop
3719 431 Statement.applyExp(stmt,
3720 function checkDeletedVarRefsInExp(deletedVars = deletedVars, settings = settings, info = Statement.info(stmt)));
3721 end for;
3722 end checkDeletedVarRefsInAlg;
3723
3724 annotation(__OpenModelica_Interface="nf_frontend");
3725 end NFFlatten;
3726