Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 62.5% 40 / 0 / 64
Functions: -% 0 / 1 / 1
Branches: 66.7% 36 / 0 / 54

OMCompiler/Compiler/NFFrontEnd/NFAlgorithm.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated uniontype NFAlgorithm
37 // OF imports
38 import DAE;
39
40 // NF imports
41 import ComponentRef = NFComponentRef;
42 import Expression = NFExpression;
43 import NFInstNode.InstNode;
44 import NFInstNode;
45 import Statement = NFStatement;
46 import Type = NFType;
47
48 // Util imports
49 import Error;
50 import Flags;
51 import UnorderedSet;
52
53 protected
54 import Algorithm = NFAlgorithm;
55
56 public
57 record ALGORITHM
58 list<Statement> statements;
59 list<ComponentRef> inputs;
60 list<ComponentRef> outputs;
61 Option<UnorderedSet<Statement>> stmtDiffInfo;
62 NFInstNode.ScopeRef scope "Weakly: that scope's sections hold
63 the algorithm.";
64 DAE.ElementSource source;
65 end ALGORITHM;
66
67 partial function ApplyFn
68 input Statement alg;
69 end ApplyFn;
70
71 function applyList
72 input list<Algorithm> algs;
73 input ApplyFn func;
74 algorithm
75 ✗ for alg in algs loop
76 ✗ for s in alg.statements loop
77 ✗ Statement.apply(s, func);
78 end for;
79 end for;
80 end applyList;
81
82 function apply
83 input Algorithm alg;
84 input ApplyFn func;
85 algorithm
86
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 196 times.
609 for s in alg.statements loop
87 413 Statement.apply(s, func);
88 end for;
89 end apply;
90
91 function applyExp
92 input Algorithm alg;
93 input ApplyFunc func;
94
95 partial function ApplyFunc
96 input Expression exp;
97 end ApplyFunc;
98 algorithm
99 ✗ for s in alg.statements loop
100 ✗ Statement.applyExp(s, func);
101 end for;
102 end applyExp;
103
104 function applyExpList
105 input list<Algorithm> algs;
106 input ApplyFunc func;
107
108 partial function ApplyFunc
109 input Expression exp;
110 end ApplyFunc;
111 algorithm
112 ✗ for alg in algs loop
113 ✗ applyExp(alg, func);
114 end for;
115 end applyExpList;
116
117 function map
118 input output Algorithm alg;
119 input MapFn fn;
120
121 partial function MapFn
122 input output Statement stmt;
123 end MapFn;
124 algorithm
125 ✗ alg.statements := list(Statement.map(s, fn) for s in alg.statements);
126 end map;
127
128 function mapExp
129 input output Algorithm alg;
130 input MapFunc func;
131
132 partial function MapFunc
133 input output Expression exp;
134 end MapFunc;
135 algorithm
136 27627 alg.statements := Statement.mapExpList(alg.statements, func);
137 end mapExp;
138
139 function mapExpList
140 input output list<Algorithm> algs;
141 input MapFunc func;
142
143 partial function MapFunc
144 input output Expression exp;
145 end MapFunc;
146 algorithm
147
4/4
✓ Branch 0 taken 20299 times.
✓ Branch 1 taken 43626 times.
✓ Branch 2 taken 20299 times.
✓ Branch 3 taken 43626 times.
63925 algs := list(mapExp(alg, func) for alg in algs);
148 end mapExpList;
149
150 function foldExp<ArgT>
151 input Algorithm alg;
152 input FoldFunc func;
153 input output ArgT arg;
154
155 partial function FoldFunc
156 input Expression exp;
157 input output ArgT arg;
158 end FoldFunc;
159 algorithm
160
2/2
✓ Branch 0 taken 129125 times.
✓ Branch 1 taken 25436 times.
154561 for s in alg.statements loop
161 129125 arg := Statement.foldExp(s, func, arg);
162 end for;
163 end foldExp;
164
165 function foldExpList<ArgT>
166 input list<Algorithm> algs;
167 input FoldFunc func;
168 input output ArgT arg;
169
170 partial function FoldFunc
171 input Expression exp;
172 input output ArgT arg;
173 end FoldFunc;
174 algorithm
175
2/2
✓ Branch 0 taken 25436 times.
✓ Branch 1 taken 53628 times.
79064 for alg in algs loop
176 25436 arg := foldExp(alg, func, arg);
177 end for;
178 end foldExpList;
179
180 function toString
181 input Algorithm alg;
182 input String indent = "";
183 output String str;
184 algorithm
185 6 str := Statement.toStringList(alg.statements, indent);
186 end toString;
187
188 function setInputsOutputs
189 input output Algorithm alg;
190 protected
191 list<ComponentRef> inputs, outputs;
192 algorithm
193 8384 (inputs, outputs) := getInputsOutputs(alg.statements);
194 8384 alg.inputs := inputs;
195 alg.outputs := outputs;
196 end setInputsOutputs;
197
198 function getInputsOutputs "This function finds the inputs and outputs of an
199 algorithm. Inputs are values that are reffered on the right hand side of any
200 statement in the algorithm and an output is a variables belonging to the
201 variables that are assigned a value in the algorithm. If a variable is an
202 input and an output it will be treated as an output."
203 input list<Statement> statements;
204 output list<ComponentRef> inputs_lst;
205 output list<ComponentRef> outputs_lst;
206 protected
207 UnorderedSet<ComponentRef> inputs_set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
208 UnorderedSet<ComponentRef> outputs_set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
209 algorithm
210 try
211
2/2
✓ Branch 0 taken 10082 times.
✓ Branch 1 taken 8408 times.
18490 for statement in statements loop
212 10082 statementInputsOutputs(statement, inputs_set, outputs_set);
213 end for;
214 8408 inputs_lst := UnorderedSet.toList(inputs_set);
215 8408 outputs_lst := UnorderedSet.toList(outputs_set);
216 else
217 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
218 ✗ fail();
219 end try;
220 end getInputsOutputs;
221
222 function isEqual
223 input Algorithm alg1;
224 input Algorithm alg2;
225 output Boolean b;
226 algorithm
227
5/6
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 53 times.
✓ Branch 5 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 53 times.
63 b := List.isEqualOnTrue(alg1.inputs, alg2.inputs, ComponentRef.isEqual)
228 and List.isEqualOnTrue(alg1.outputs, alg2.outputs, ComponentRef.isEqual)
229 and List.isEqualOnTrue(alg1.statements, alg2.statements, Statement.isEqual);
230 end isEqual;
231
232 function isEmpty
233 input Algorithm alg;
234 output Boolean b = listEmpty(alg.statements);
235 end isEmpty;
236
237 function isDiscrete
238 "returns true if the algorithm contains any discrete outputs"
239 input Algorithm alg;
240 output Boolean b;
241 algorithm
242 46 b := List.any(alg.outputs, ComponentRef.isDiscrete);
243
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 17 times.
46 b := if b then b else List.any(alg.statements, Statement.isDiscrete);
244 end isDiscrete;
245
246 protected
247 function statementInputsOutputs "Helper for getInputsOutputs.
248 Traverse statements and find inputs and outputs"
249 input Statement statement;
250 input UnorderedSet<ComponentRef> inputs_set;
251 input UnorderedSet<ComponentRef> outputs_set;
252 algorithm
253 () := match statement
254 local
255 Expression lhs, rhs;
256 list<Expression> elements;
257 list<Statement> stmts;
258 list<tuple<Expression, list<Statement>>> branches;
259
260 // a := expr;
261 case Statement.ASSIGNMENT(lhs = lhs as Expression.CREF(), rhs = rhs) algorithm
262 // TODO extend for array, matrix?
263 // TODO has to be scalarized if scalarize
264 3101 Expression.apply(rhs, function expressionInputs(inputs_set = inputs_set, outputs_set = outputs_set));
265 3101 expressionOutput(lhs, inputs_set, outputs_set);
266 then ();
267
268 // (a, b, c, ...) := expr;
269 case Statement.ASSIGNMENT(lhs = Expression.TUPLE(elements = elements), rhs = rhs) algorithm
270 // TODO extend for array, matrix?
271 145 Expression.apply(rhs, function expressionInputs(inputs_set = inputs_set, outputs_set = outputs_set));
272
2/2
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 145 times.
681 for exp in elements loop
273 536 expressionOutput(exp, inputs_set, outputs_set);
274 end for;
275 then ();
276
277 // ToDo: Statement.ASSIGNMENT(lhs=lhs as Expression.RECORD_ELEMENT())
278
279 case Statement.FOR(body = stmts) algorithm
280
2/2
✓ Branch 0 taken 593 times.
✓ Branch 1 taken 529 times.
1122 for stmt in stmts loop
281 593 statementInputsOutputs(stmt, inputs_set, outputs_set);
282 end for;
283 then ();
284
285 case Statement.IF(branches = branches) algorithm
286
2/2
✓ Branch 0 taken 1115 times.
✓ Branch 1 taken 820 times.
1935 for branch in branches loop
287 1115 (_, stmts) := branch;
288 // TODO warn about using unassigned outputs in condition -> const eval?
289
2/2
✓ Branch 0 taken 1597 times.
✓ Branch 1 taken 1115 times.
2712 for stmt in stmts loop
290 1597 statementInputsOutputs(stmt, inputs_set, outputs_set);
291 end for;
292 end for;
293 // TODO input in one branch can't be output in another etc...
294 then ();
295
296 case Statement.WHEN(branches = branches) algorithm
297
2/2
✓ Branch 0 taken 468 times.
✓ Branch 1 taken 432 times.
900 for branch in branches loop
298 468 (_, stmts) := branch;
299 // what about using unassigned outputs in condition?
300
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 468 times.
1107 for stmt in stmts loop
301 639 statementInputsOutputs(stmt, inputs_set, outputs_set);
302 end for;
303 end for;
304 // TODO input in one branch can't be output in another etc...
305 then ();
306
307 case Statement.WHILE(body = stmts) algorithm
308 // TODO warn about using unassigned outputs in condition -> const eval?
309 ✗ for stmt in stmts loop
310 ✗ statementInputsOutputs(stmt, inputs_set, outputs_set);
311 end for;
312 then ();
313
314 case Statement.ASSERT() then ();
315 case Statement.TERMINATE() then ();
316 case Statement.REINIT() then ();
317 case Statement.NORETCALL() then ();
318 case Statement.RETURN() then ();
319 case Statement.BREAK() then ();
320 case Statement.FAILURE() then ();
321
322 case Statement.FUNCTION_ARRAY_INIT()
323 algorithm
324 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed due to wrong Statement Type: FUNCTION_ARRAY_INIT."});
325 ✗ then fail();
326
327 else
328 algorithm
329 ✗ if Flags.isSet(Flags.FAILTRACE) then
330 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed for " + Statement.toString(statement)});
331 end if;
332 ✗ then fail();
333
334 end match;
335 end statementInputsOutputs;
336
337 function expressionInputs
338 "finds all inputs on the rhs of a statement"
339 input Expression exp;
340 input UnorderedSet<ComponentRef> inputs_set;
341 input UnorderedSet<ComponentRef> outputs_set "outputs from previous statements";
342 algorithm
343 () := match exp
344 local
345 ComponentRef cr;
346 Type ty;
347
348 // Skip time
349 case Expression.CREF(cref = cr) guard(ComponentRef.isTime(cr)) then ();
350
351 // Skip iterators
352 case Expression.CREF(cref = cr) guard ComponentRef.isIterator(cr) then ();
353
354 // Skip external Objects
355 case Expression.CREF(ty = ty) guard(Type.isExternalObject(ty)) then ();
356
357 case Expression.CREF(cref = cr) algorithm
358 // since outputs get stripped, also strip inputs
359 // otherwise uninitialized output detection doesn't work properly
360 7493 cr := ComponentRef.stripSubscriptsAll(cr);
361
2/2
✓ Branch 1 taken 5033 times.
✓ Branch 2 taken 2460 times.
7493 if not UnorderedSet.contains(cr, outputs_set) then
362 5033 UnorderedSet.add(cr, inputs_set);
363 end if;
364 then ();
365
366 else ();
367 end match;
368 end expressionInputs;
369
370 function expressionOutput "author: Frenkel TUD 2012-06
371 detects outputs by looking at crefs in the lhs of a statement"
372 input Expression exp "should be a cref, otherwise fail";
373 input UnorderedSet<ComponentRef> inputs_set;
374 input UnorderedSet<ComponentRef> outputs_set;
375 algorithm
376 () := match exp
377 local
378 ComponentRef cr;
379 Type ty;
380
381 // Skip wild
382 case Expression.CREF(cref = ComponentRef.WILD()) then ();
383
384 // time is not an output in algorithms
385 case Expression.CREF(cref = cr) guard(ComponentRef.isTime(cr)) algorithm
386 ✗ Error.addMessage(Error.COMPILER_ERROR, {"Trying to assign to time."});
387 ✗ then fail();
388
389 // Iterators are not outputs in algorithms
390 case Expression.CREF(cref = cr) guard ComponentRef.isIterator(cr) algorithm
391 ✗ Error.addMessage(Error.COMPILER_ERROR, {"Trying to assign to iterator " + ComponentRef.toString(cr) + "."});
392 ✗ then fail();
393
394 // Skip external Objects
395 // or error?
396 case Expression.CREF(ty = ty) guard(Type.isExternalObject(ty)) then ();
397
398 case Expression.CREF(cref = cr) algorithm
399 /* mahge:
400 Modelica spec 3.3 rev 11.1.2
401 "If at least one element of an array appears on the left hand side of
402 the assignment operator, then the complete array is initialized in
403 this algorithm section"
404 So we strip the all subs except for model subs and send the whole array to expansion. i.e. we consider the whole array as modified.
405 */
406 3635 cr := ComponentRef.stripSubscriptsAll(cr);
407
2/2
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 3461 times.
3635 if UnorderedSet.remove(cr, inputs_set) then
408
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
174 if Flags.isSet(Flags.FAILTRACE) then
409 ✗ Error.addMessage(Error.COMPILER_WARNING, {"Using output variable in RHS before it is assigned (former occurences will be set to initial value): " + Expression.toString(exp)});
410 end if;
411 // TODO add to outputs that need to be initialized / partially replaced by initial value?
412 end if;
413 3635 UnorderedSet.add(cr, outputs_set);
414 then ();
415
416 else algorithm
417 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed due to wrong expression type in LHS of algorithm statement: " + Expression.toString(exp)});
418 ✗ then fail();
419 end match;
420 end expressionOutput;
421
422 annotation(__OpenModelica_Interface="nf_frontend");
423 end NFAlgorithm;
424