Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 66.7% 18 / 0 / 27
Functions: -% 0 / 1 / 1
Branches: 75.0% 9 / 0 / 12

OMCompiler/Compiler/NFFrontEnd/NFFunctionInverse.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 NFFunctionInverse
37 import Absyn;
38 import ComponentRef = NFComponentRef;
39 import Expression = NFExpression;
40 import NFFunction.Function;
41 import NFInstNode.InstNode;
42 import SCode;
43 import Type = NFType;
44
45 protected
46 import Call = NFCall;
47 import DAE;
48 import Inst = NFInst;
49 import Lookup = NFLookup;
50 import SCodeUtil;
51 import Typing = NFTyping;
52
53 import FunctionInverse = NFFunctionInverse;
54
55 public
56 record FUNCTION_INV
57 ComponentRef inputParam;
58 Expression inverseCall;
59 SourceInfo info;
60 end FUNCTION_INV;
61
62 function instInverses
63 input InstNode fnNode;
64 input Function fn;
65 output array<FunctionInverse> inverses;
66 protected
67 list<SCode.Mod> inv_mods;
68 list<FunctionInverse> invs = {};
69 algorithm
70 23760 inv_mods := getInverseAnnotations(InstNode.definition(fnNode));
71
72
4/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 23672 times.
✓ Branch 3 taken 87 times.
✓ Branch 4 taken 1 time.
23760 if not listEmpty(inv_mods) and not listLength(fn.outputs) == 1 then
73 2 Error.addSourceMessage(Error.FUNCTION_INVALID_OUTPUTS_FOR_INVERSE,
74 {AbsynUtil.pathString(Function.name(fn))},
75 SCodeUtil.getModifierInfo(listHead(inv_mods)));
76 1 fail();
77 end if;
78
79
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 23759 times.
23846 for m in inv_mods loop
80 87 invs := instInverseMod(m, fnNode, fn, invs);
81 end for;
82
83 23759 inverses := listArray(invs);
84 end instInverses;
85
86 function typeInverse
87 input output FunctionInverse fnInv;
88 algorithm
89 48 fnInv.inputParam := Typing.typeCref(fnInv.inputParam, NFInstContext.RELAXED, fnInv.info);
90 fnInv.inverseCall := Typing.typeExp(fnInv.inverseCall, NFInstContext.RELAXED, fnInv.info);
91 end typeInverse;
92
93 function toDAE
94 input FunctionInverse fnInv;
95 output DAE.FunctionDefinition invDef;
96 algorithm
97 45 invDef := DAE.FunctionDefinition.FUNCTION_INVERSE(
98 ComponentRef.toDAE(fnInv.inputParam), Expression.toDAE(fnInv.inverseCall));
99 end toDAE;
100
101 function toSubMod
102 input FunctionInverse fnInv;
103 output SCode.SubMod subMod;
104 protected
105 SCode.SubMod inv_mod;
106 Absyn.Exp call_exp;
107 algorithm
108 ✗ call_exp := Expression.toAbsyn(fnInv.inverseCall);
109 ✗ inv_mod := SCode.SubMod.NAMEMOD(ComponentRef.firstName(fnInv.inputParam),
110 SCode.Mod.MOD(SCode.Final.NOT_FINAL(), SCode.Each.NOT_EACH(), {}, SOME(call_exp), NONE(), fnInv.info));
111 ✗ subMod := SCode.SubMod.NAMEMOD("inverse",
112 SCode.Mod.MOD(SCode.Final.NOT_FINAL(), SCode.Each.NOT_EACH(), {inv_mod}, NONE(), NONE(), fnInv.info));
113 end toSubMod;
114
115 function getFunction
116 input FunctionInverse fnInv;
117 output Function fn;
118 protected
119 Call call;
120 algorithm
121 ✗ Expression.CALL(call = call) := fnInv.inverseCall;
122 ✗ fn := Call.typedFunction(call);
123 end getFunction;
124
125 protected
126 function getInverseAnnotations
127 input SCode.Element definition;
128 output list<SCode.Mod> invMods;
129 algorithm
130 invMods := match definition
131 local
132 SCode.Annotation ann;
133
134 case SCode.Element.CLASS(cmt = SCode.Comment.COMMENT(annotation_ = SOME(ann)))
135 20444 then SCodeUtil.lookupAnnotations(ann, "inverse");
136
137 else {};
138 end match;
139 end getInverseAnnotations;
140
141 function instInverseMod
142 input SCode.Mod mod;
143 input InstNode fnNode;
144 input Function fn;
145 input output list<FunctionInverse> fnInvs;
146 algorithm
147 fnInvs := match mod
148 case SCode.Mod.MOD()
149 algorithm
150
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 87 times.
174 for s in mod.subModLst loop
151 87 fnInvs := instInverseSubMod(s, fnNode, fn, mod.info, fnInvs);
152 end for;
153 then
154 fnInvs;
155
156 else
157 algorithm
158 ✗ Error.terminate(getInstanceName() + " got invalid modifier", sourceInfo());
159 ✗ then
160 fail();
161
162 end match;
163 end instInverseMod;
164
165 function instInverseSubMod
166 input SCode.SubMod submod;
167 input InstNode fnNode;
168 input Function fn;
169 input SourceInfo info;
170 input output list<FunctionInverse> fnInvs;
171 protected
172 String name;
173 Absyn.ComponentRef aparam;
174 ComponentRef param;
175 Absyn.Exp call_aexp;
176 Expression call_exp;
177 algorithm
178 fnInvs := match submod
179 // inverse(u = fn(...))
180 case SCode.SubMod.NAMEMOD(ident = name, mod = SCode.Mod.MOD(
181 subModLst = {}, binding = SOME(call_aexp as Absyn.Exp.CALL())))
182 algorithm
183 86 aparam := Absyn.ComponentRef.CREF_IDENT(name, {});
184
185 // u must be an input parameter of the function that contains the inverse annotation.
186 try
187 86 param := Lookup.lookupLocalCref(aparam, fnNode, NFInstContext.RELAXED, info);
188
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
86 true := InstNode.isInput(ComponentRef.node(param));
189 else
190 ✗ Error.addSourceMessage(Error.INVALID_FUNCTION_ANNOTATION_INPUT,
191 {name, AbsynUtil.pathString(Function.name(fn))}, info);
192 ✗ fail();
193 end try;
194
195 86 call_exp := Inst.instExp(call_aexp, fnNode, NFInstContext.RELAXED, info);
196 86 then
197 FUNCTION_INV(param, call_exp, info) :: fnInvs;
198
199 case SCode.SubMod.NAMEMOD()
200 algorithm
201 2 Error.addStrictMessage(Error.INVALID_FUNCTION_ANNOTATION_ATTR,
202 {submod.ident + SCodeDump.printModStr(submod.mod), "inverse"}, info);
203 then
204 fnInvs;
205
206 end match;
207 end instInverseSubMod;
208
209 annotation(__OpenModelica_Interface="nf_frontend");
210 end NFFunctionInverse;
211