Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 79.0% 94 / 0 / 119
Functions: -% 0 / 1 / 1
Branches: 69.2% 54 / 0 / 78

OMCompiler/Compiler/NBackEnd/Util/NBReplacements.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 NBReplacements
37 "file: NBReplacements.mo
38 package: NBReplacements
39 description:
40 Replacements consists of a mapping between variables and expressions, the first binary tree of this type.
41 To eliminate a variable from an equation system a replacement rule varname->expression is added to this
42 datatype.
43 To be able to update these replacement rules incrementally a backward lookup mechanism is also required.
44 For instance, having a rule a->b and adding a rule b->c requires to find the first rule a->b and update it to
45 a->c. This is what the second binary tree is used for.
46 "
47
48 protected
49 // rename self import
50 import Replacements = NBReplacements;
51
52 // OF imports
53 import Absyn;
54
55 // NF imports
56 import Binding = NFBinding;
57 import Call = NFCall;
58 import ComponentRef = NFComponentRef;
59 import Expression = NFExpression;
60 import NFInstNode.InstNode;
61 import InstContext = NFInstContext;
62 import NFFunction.Function;
63 import SimplifyExp = NFSimplifyExp;
64 import Statement = NFStatement;
65 import Subscript = NFSubscript;
66 import Type = NFType;
67 import Typing = NFTyping;
68 import Variable = NFVariable;
69
70 // Backend imports
71 import BVariable = NBVariable;
72 import NBEquation.{EqData, Equation, EquationPointers};
73 import Inline = NBInline;
74 import Slice = NBSlice;
75 import Solve = NBSolve;
76 import StrongComponent = NBStrongComponent;
77 import NBVariable.{VarData, VariablePointers};
78
79 // Util
80 import StringUtil;
81
82 public
83 // =========================================================================
84 // COMPONENT REFERENCE REPLACEMENT
85 // =========================================================================
86
87 function single
88 "performs a single replacement"
89 input output Expression exp "Replacement happens inside this expression";
90 input Expression old "Replaced by new";
91 input Expression new "Replaces old";
92 protected
93 function traverse
94 input output Expression exp;
95 input Expression old;
96 input Expression new;
97 algorithm
98
2/2
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 97 times.
265 exp := if Expression.isEqual(exp, old) then new else exp;
99 end traverse;
100 algorithm
101 93 exp := Expression.map(exp, function traverse(old = old, new = new));
102 end single;
103
104 function simple
105 "creates simple replacement rules for alias removal"
106 input list<StrongComponent> comps;
107 input UnorderedMap<ComponentRef, Expression> replacements;
108 algorithm
109
2/2
✓ Branch 0 taken 1936 times.
✓ Branch 1 taken 1105 times.
3041 for comp in comps loop
110 1936 addSimple(comp, replacements);
111 end for;
112 end simple;
113
114 function addSimple
115 "ToDo: More cases!"
116 input StrongComponent comp;
117 input UnorderedMap<ComponentRef, Expression> replacements;
118 algorithm
119 () := match comp
120 local
121 ComponentRef varName;
122 Equation solvedEq;
123 Solve.Status status;
124 Expression replace_exp;
125
126 case StrongComponent.SINGLE_COMPONENT() algorithm
127 // solve the equation for the variable
128 1920 varName := BVariable.getVarName(comp.var);
129 1920 (solvedEq, status, _) := Solve.solveBody(Pointer.access(comp.eqn), varName);
130
1/2
✓ Branch 0 taken 1920 times.
✗ Branch 1 not taken.
1920 if status == NBSolve.Status.EXPLICIT then
131 // apply all previous replacements on the RHS
132
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1920 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1920 times.
1920 SOME(replace_exp) := Equation.getRHS(solvedEq);
133 1920 replace_exp := Expression.map(replace_exp, function applySimpleExp(replacements = replacements));
134 1920 replace_exp := SimplifyExp.simplifyDump(replace_exp, true, getInstanceName());
135 // add the new replacement rule
136 1920 addInputArgTpl((varName, replace_exp) , replacements, true);
137 else
138 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component cannot be solved explicitly: " + StrongComponent.toString(comp)});
139 ✗ fail();
140 end if;
141 then ();
142
143 case StrongComponent.SLICED_COMPONENT() algorithm
144 // solve the equation for the variable
145 16 varName := BVariable.getVarName(Slice.getT(comp.var));
146 16 (solvedEq, status, _) := Solve.solveBody(Pointer.access(Slice.getT(comp.eqn)), varName);
147
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if status == NBSolve.Status.EXPLICIT then
148 // apply all previous replacements on the RHS
149
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
16 SOME(replace_exp) := Equation.getRHS(solvedEq);
150 16 replace_exp := Expression.map(replace_exp, function applySimpleExp(replacements = replacements));
151 16 replace_exp := SimplifyExp.simplifyDump(replace_exp, true, getInstanceName());
152 // add the new replacement rule
153 16 addInputArgTpl((varName, replace_exp) , replacements, true);
154 else
155 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component cannot be solved explicitly: " + StrongComponent.toString(comp)});
156 ✗ fail();
157 end if;
158 then ();
159
160 else algorithm
161 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component is not simple: " + StrongComponent.toString(comp)});
162 ✗ then fail();
163 end match;
164 end addSimple;
165
166 function applySimple
167 "Used for alias removal.
168 This should be applied before partitioning. Otherwise all systems have to be checked for jacobians
169 and hessians on which this also has to be applied. Can be applied on single jacobians and hessians
170 while removing simple equations on them."
171 input output EqData eqData;
172 input output VarData varData; // bindings
173 input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here";
174 protected
175 list<tuple<ComponentRef, Expression>> entries;
176 ComponentRef aliasCref;
177 Expression replacement;
178 Pointer<Variable> var_ptr;
179 Variable var;
180 algorithm
181 // do nothing if replacements are empty
182
2/2
✓ Branch 1 taken 287 times.
✓ Branch 2 taken 93 times.
380 if UnorderedMap.isEmpty(replacements) then return; end if;
183 186 eqData := EqData.mapExp(eqData, function applySimpleExp(replacements = replacements), SOME(function applySimpleCref(replacements = replacements)));
184
185 // apply on bindings (is this necessary?)
186 varData := match varData
187 case VarData.VAR_DATA_SIM() algorithm
188 186 varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements));
189 186 varData.aliasVars := VariablePointers.map(varData.aliasVars, function applySimpleVar(replacements = replacements));
190 then varData;
191 case VarData.VAR_DATA_JAC() algorithm
192 ✗ varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements));
193 then varData;
194 case VarData.VAR_DATA_HES() algorithm
195 ✗ varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements));
196 then varData;
197 end match;
198
199 // update alias variable bindings
200 93 entries := UnorderedMap.toList(replacements);
201
2/2
✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 93 times.
2123 for entry in entries loop
202 2030 (aliasCref, replacement) := entry;
203 2030 var_ptr := BVariable.getVarPointer(aliasCref, sourceInfo());
204 2030 var := Pointer.access(var_ptr);
205 2030 var.binding := Binding.update(var.binding, replacement);
206 2030 Pointer.update(var_ptr, var);
207 end for;
208 end applySimple;
209
210 function applySimpleExp
211 "Needs to be mapped with Expression.map()"
212 input output Expression exp "Replacement happens inside this expression";
213 input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here";
214 algorithm
215 exp := match exp
216 local
217 Expression res;
218 ComponentRef stripped;
219 list<Subscript> subs;
220
221 case Expression.CREF() algorithm
222
2/2
✓ Branch 1 taken 11820 times.
✓ Branch 2 taken 25153 times.
36973 if UnorderedMap.contains(exp.cref, replacements) then
223 // the cref (with subscripts) is found in replacements
224 11820 res := UnorderedMap.getOrFail(exp.cref, replacements);
225 else
226 // try to strip the subscripts and see if that cref occurs
227 25153 stripped := ComponentRef.stripSubscriptsAll(exp.cref);
228
2/2
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 24943 times.
25153 if UnorderedMap.contains(stripped, replacements) then
229 210 subs := ComponentRef.subscriptsAllWithWholeFlat(exp.cref);
230 210 res := UnorderedMap.getOrFail(stripped, replacements);
231 210 res := Expression.applySubscripts(subs, res, true);
232 else
233 // do nothing
234 res := exp;
235 end if;
236 end if;
237 then res;
238 else exp;
239 end match;
240 end applySimpleExp;
241
242 function applySimpleCref
243 "Needs to be used as funcCref in Equation.map() to replace crefs that appear
244 as direct ComponentRef arguments (e.g. the state variable of a reinit statement)."
245 input output ComponentRef cref;
246 input UnorderedMap<ComponentRef, Expression> replacements;
247 protected
248 Expression replacement;
249 algorithm
250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 402 times.
402 if UnorderedMap.contains(cref, replacements) then
251 ✗ replacement := UnorderedMap.getOrFail(cref, replacements);
252 cref := match replacement
253 ✗ case Expression.CREF() then replacement.cref;
254 else cref;
255 end match;
256 end if;
257 end applySimpleCref;
258
259 function applySimpleVar
260 "applys replacement on the variable binding expression"
261 input output Variable var;
262 input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here";
263 algorithm
264 var := match var
265 local
266 Binding binding;
267 case Variable.VARIABLE(binding = binding as Binding.TYPED_BINDING()) algorithm
268 5488 binding.bindingExp := Expression.map(binding.bindingExp, function applySimpleExp(replacements = replacements));
269 2744 var.binding := binding;
270 then var;
271 else var;
272 end match;
273 end applySimpleVar;
274
275 function replaceVarPtr
276 "replaces a pointer if there is a name replacement in the map"
277 input output Pointer<Variable> var_ptr;
278 input UnorderedMap<ComponentRef, ComponentRef> replacements;
279 protected
280 Option<ComponentRef> cref;
281 algorithm
282 ✗ cref := UnorderedMap.get(BVariable.getVarName(var_ptr), replacements);
283 ✗ if isSome(cref) then
284 ✗ var_ptr := BVariable.getVarPointer(Util.getOption(cref), sourceInfo());
285 end if;
286 end replaceVarPtr;
287
288 function simpleToString
289 input UnorderedMap<ComponentRef, Expression> replacements;
290 output String str = "";
291 protected
292 list<tuple<ComponentRef, Expression>> entries;
293 String constStr="", aliasStr="", nonTrivialStr="";
294 ComponentRef key;
295 Expression value;
296 algorithm
297 14 entries := UnorderedMap.toList(replacements);
298
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 14 times.
40 for entry in entries loop
299 26 (key, value) := entry;
300
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 10 times.
26 if Expression.isConstNumber(value) then
301 // constant alias
302 16 constStr := constStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n";
303 elseif not Expression.isTrivialCref(value) then
304 // non trivial alias
305 6 nonTrivialStr := nonTrivialStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n";
306 else
307 // trivial alias
308 4 aliasStr := aliasStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n";
309 end if;
310 end for;
311 14 str := str + StringUtil.headline_4("[dumprepl] Constant Replacements:") + constStr;
312 14 str := str + StringUtil.headline_4("[dumprepl] Trivial Alias Replacements:") + aliasStr;
313 14 str := str + StringUtil.headline_4("[dumprepl] Nontrivial Alias Replacements:") + nonTrivialStr;
314 end simpleToString;
315
316 // =========================================================================
317 // FUNCTION BODY REPLACEMENT
318 // =========================================================================
319
320 function replaceFunctions
321 "replaces all function calls in the replacements map with their body expressions,
322 if possible."
323 input output EqData eqData;
324 input VariablePointers variables;
325 input UnorderedMap<Absyn.Path, Function> replacements;
326 protected
327 UnorderedMap<Expression, Expression> prev_replacements = UnorderedMap.new<Expression>(Expression.hash, Expression.isEqual);
328 algorithm
329 // do nothing if replacements are empty
330
2/2
✓ Branch 1 taken 514 times.
✓ Branch 2 taken 55 times.
569 if UnorderedMap.isEmpty(replacements) then return; end if;
331 55 eqData := EqData.mapExp(eqData, function applyFuncExp(replacements = replacements, prev_replacements = prev_replacements, variables = variables));
332 end replaceFunctions;
333
334 function applyFuncExp
335 "Needs to be mapped with Expression.map()"
336 input output Expression exp "Replacement happens inside this expression";
337 input UnorderedMap<Absyn.Path, Function> replacements "rules for replacements are stored inside here";
338 input UnorderedMap<Expression, Expression> prev_replacements "previously found replacements that need not be done again";
339 input VariablePointers variables;
340 algorithm
341 exp := match exp
342 local
343 Call call;
344 Function fn;
345 UnorderedMap<ComponentRef, Expression> local_replacements;
346 list<ComponentRef> input_crefs;
347 ComponentRef local_cref;
348 Option<Expression> binding_exp_opt;
349 Expression binding_exp, body_exp, res_exp;
350
351 case Expression.CALL(call = call as Call.TYPED_CALL(fn = fn)) guard(UnorderedMap.contains(fn.path, replacements)) algorithm
352 // check if the function was previously replaced
353 res_exp := match UnorderedMap.get(exp, prev_replacements)
354 case SOME(res_exp) then res_exp;
355 else algorithm
356 // use the function from the tree, in case it was changed
357 336 fn := UnorderedMap.getOrFail(fn.path, replacements);
358
359 // map all the inputs to the arguments and add to local replacement map
360 336 local_replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
361
4/4
✓ Branch 0 taken 629 times.
✓ Branch 1 taken 336 times.
✓ Branch 2 taken 629 times.
✓ Branch 3 taken 336 times.
965 input_crefs := list(ComponentRef.fromNode(node, InstNode.getType(node)) for node in fn.inputs);
362 // ToDo: rather use the function slots for this?
363
2/2
✓ Branch 1 taken 629 times.
✓ Branch 2 taken 336 times.
965 for tpl in List.zip(input_crefs, call.arguments) loop
364 629 addInputArgTpl(tpl, local_replacements, false);
365 end for;
366
367 // add replacement rules for local (protected) variables
368
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 336 times.
337 for local_node in fn.locals loop
369 1 local_cref := ComponentRef.fromNode(local_node, InstNode.getType(local_node));
370 1 binding_exp_opt := InstNode.getBindingExpOpt(local_node);
371
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if isSome(binding_exp_opt) then
372 // replace binding expression with already gathered input replacements
373 1 binding_exp := Expression.map(Util.getOption(binding_exp_opt), function applySimpleExp(replacements = local_replacements));
374 else
375 // add a "wild" binding. This will result in unused outputs being ignored.
376 binding_exp := Expression.CREF(Type.UNKNOWN(), ComponentRef.WILD());
377 end if;
378 1 addInputArgTpl((local_cref, binding_exp), local_replacements, false);
379 end for;
380
381 // get the expression from function body (fails if its not a single replacable assignment)
382 336 body_exp := Function.getSingleBodyExp(fn);
383 // replace input withs arguments in expression
384 336 body_exp := Expression.map(body_exp, function applySimpleExp(replacements = local_replacements));
385 // if any of the inputs had an undetermined size, retype the new body
386
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 293 times.
336 if not List.all(input_crefs, ComponentRef.sizeKnown) then
387 43 body_exp := Typing.typeExp(body_exp, NFInstContext.RHS, sourceInfo(), true);
388 end if;
389
390 // combine binaries and simplify
391 336 body_exp := SimplifyExp.combineBinaries(body_exp);
392 336 body_exp := SimplifyExp.simplifyDump(body_exp, true, getInstanceName());
393
394 // replace body with possible nested functions
395 336 res_exp := Expression.map(body_exp, function applyFuncExp(replacements = replacements, prev_replacements = prev_replacements, variables = variables));
396
397 // wrap all event triggering expressions in noEvent() if the function is not supposed to trigger events
398
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 if not fn.attributes.generateEvents then
399 336 res_exp := Expression.fakeMap(res_exp, wrapEvents);
400 end if;
401
402 // add the new replacement to the map
403 336 UnorderedMap.add(exp, res_exp, prev_replacements);
404
405
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 336 times.
336 if Flags.isSet(Flags.DUMPBACKENDINLINE) then
406 ✗ print("[" + getInstanceName() + "] Inlining: " + Expression.toString(exp) + "\n");
407 ✗ print("-- Result: " + Expression.toString(body_exp) + "\n\n");
408 end if;
409 then res_exp;
410 end match;
411 then res_exp;
412
413 else exp;
414 end match;
415 end applyFuncExp;
416
417 function addInputArgTpl
418 "adds an input to argument replacement and also adds
419 all record children replacements."
420 input tuple<ComponentRef, Expression> tpl;
421 input UnorderedMap<ComponentRef, Expression> replacements;
422 input Boolean lowered_lhs "true if the LHS has properly lowered (backend) crefs";
423 protected
424 ComponentRef cref;
425 Expression arg;
426 list<Expression> children_args;
427 list<ComponentRef> children, tmp;
428 Call call;
429 Function fn;
430 algorithm
431 3392 (cref, arg) := tpl;
432 3392 UnorderedMap.add(cref, arg, replacements);
433
434 // also try to add record children replacements (throw error if impossible?)
435
2/2
✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 1353 times.
3392 children := if lowered_lhs then BVariable.getRecordChildrenCref(cref) else ComponentRef.getRecordChildren(cref);
436
2/2
✓ Branch 0 taken 3160 times.
✓ Branch 1 taken 232 times.
3392 if not listEmpty(children) then
437 children_args := match arg
438
439 // if the argument is a cref, get its children
440 case Expression.CREF() algorithm
441 200 tmp := BVariable.getRecordChildrenCref(arg.cref);
442
4/4
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 495 times.
✓ Branch 3 taken 200 times.
695 then list(recordChildArg(child) for child in tmp);
443
444 // if it is a basic record, take its elements
445 8 case Expression.RECORD() then arg.elements;
446 ✗ case Expression.TUPLE() then arg.elements;
447
448 // if the argument is a record constructor, map it to its attributes
449 case Expression.CALL(call = call as Call.TYPED_CALL(fn = fn)) algorithm
450
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if Function.isDefaultRecordConstructor(fn) then
451 ✗ children_args := call.arguments;
452 elseif Function.isNonDefaultRecordConstructor(fn) then
453 // ToDo: this has to be mapped correctly with the body.
454 // for non default record constructors its not always the
455 // case that inputs map 1:1 to attributes
456 ✗ children_args := call.arguments;
457 else
458 24 children_args := Expression.getRecordElements(arg);
459 end if;
460 then children_args;
461
462 ✗ else Expression.getRecordElements(arg);
463 end match;
464
465 // check if children and children_args can be mapped to one another
466
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 232 times.
232 if List.compareLength(children, children_args) == 0 then
467
2/2
✓ Branch 1 taken 826 times.
✓ Branch 2 taken 232 times.
1058 for child_tpl in List.zip(children, children_args) loop
468 826 addInputArgTpl(child_tpl, replacements, lowered_lhs);
469 end for;
470 end if;
471 end if;
472 end addInputArgTpl;
473
474 function recordChildArg
475 "constant record children are replaced by their literal binding, since constants
476 are not assigned at runtime and are only referenced after inlining."
477 input ComponentRef child;
478 output Expression exp = Expression.fromCref(child);
479 protected
480 Pointer<Variable> var_ptr;
481 Variable var;
482 Option<Expression> binding;
483 algorithm
484
2/2
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 450 times.
495 if listEmpty(ComponentRef.subscriptsAllFlat(child)) then
485 450 var_ptr := BVariable.getVarPointer(child, sourceInfo());
486
1/2
✓ Branch 1 taken 450 times.
✗ Branch 2 not taken.
450 if BVariable.isConst(var_ptr) then
487 ✗ var := Pointer.access(var_ptr);
488 ✗ binding := Binding.typedExp(var.binding);
489 ✗ if isSome(binding) and Expression.isLiteral(Util.getOption(binding)) then
490 ✗ exp := Util.getOption(binding);
491 end if;
492 end if;
493 end if;
494 end recordChildArg;
495
496 function wrapEvents
497 input output Expression exp;
498 algorithm
499 exp := match exp
500 case Expression.IF() algorithm
501 // wrap the condition in noEvent() if it does not have a noEvent() yet
502 exp.condition := match exp.condition
503 10 case Expression.CALL() guard(Expression.isCallNamed(exp.condition, "noEvent")) then exp.condition;
504 7 else Expression.CALL(Call.makeTypedCall(
505 fn = NFBuiltinFuncs.NO_EVENT,
506 args = {exp.condition},
507 variability = Expression.variability(exp.condition),
508 purity = NFPrefixes.Purity.PURE));
509 end match;
510 17 exp.trueBranch := Expression.mapShallow(exp.trueBranch, wrapEvents);
511 17 exp.falseBranch := Expression.mapShallow(exp.falseBranch, wrapEvents);
512 then exp;
513
514 // wrap all relations in noEvent()
515 case Expression.RELATION() algorithm
516 4 then Expression.CALL(Call.makeTypedCall(
517 fn = NFBuiltinFuncs.NO_EVENT,
518 args = {exp},
519 variability = Expression.variability(exp),
520 purity = NFPrefixes.Purity.PURE));
521
522 // wrap all logical binaries in noEvent()
523 case Expression.LBINARY() algorithm
524 ✗ then Expression.CALL(Call.makeTypedCall(
525 fn = NFBuiltinFuncs.NO_EVENT,
526 args = {exp},
527 variability = Expression.variability(exp),
528 purity = NFPrefixes.Purity.PURE));
529
530 // wrap all logical unaries in noEvent()
531 case Expression.LUNARY() algorithm
532 ✗ then Expression.CALL(Call.makeTypedCall(
533 fn = NFBuiltinFuncs.NO_EVENT,
534 args = {exp},
535 variability = Expression.variability(exp),
536 purity = NFPrefixes.Purity.PURE));
537
538 5616 else Expression.mapShallow(exp, wrapEvents);
539 end match;
540 end wrapEvents;
541
542 annotation(__OpenModelica_Interface="nbackend");
543 end NBReplacements;
544