OMCompiler/Compiler/FrontEnd/SCodeInstUtil.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 SCodeInstUtil | ||
| 37 | " file: SCodeInstUtil.mo | ||
| 38 | package: SCodeInstUtil | ||
| 39 | description: Utility functions for the SCode intermediate form for calling from the frontend" | ||
| 40 | |||
| 41 | import Absyn; | ||
| 42 | import SCode; | ||
| 43 | |||
| 44 | protected | ||
| 45 | |||
| 46 | import List; | ||
| 47 | import SCodeDump; | ||
| 48 | import SCodeUtil; | ||
| 49 | |||
| 50 | protected function constantBindingOrNone | ||
| 51 | "@author: adrpo | ||
| 52 | keeps the constant binding and if not returns none" | ||
| 53 | input Option<Absyn.Exp> inBinding; | ||
| 54 | output Option<Absyn.Exp> outBinding; | ||
| 55 | algorithm | ||
| 56 | outBinding := match inBinding | ||
| 57 | local | ||
| 58 | Absyn.Exp e; | ||
| 59 | |||
| 60 | // keep it | ||
| 61 | case SOME(e) | ||
| 62 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
|
9 | then if listEmpty(AbsynUtil.getCrefFromExp(e, true, true)) then inBinding else NONE(); |
| 63 | // else | ||
| 64 | else NONE(); | ||
| 65 | end match; | ||
| 66 | end constantBindingOrNone; | ||
| 67 | |||
| 68 | public function removeNonConstantBindingsKeepRedeclares | ||
| 69 | "@author: adrpo | ||
| 70 | keeps the redeclares and removes all non-constant bindings! | ||
| 71 | if onlyRedeclare is true then bindings are removed completely!" | ||
| 72 | input SCode.Mod inMod; | ||
| 73 | input Boolean onlyRedeclares; | ||
| 74 | output SCode.Mod outMod; | ||
| 75 | algorithm | ||
| 76 | outMod := match inMod | ||
| 77 | local | ||
| 78 | list<SCode.SubMod> sl; | ||
| 79 | SCode.Final fp; | ||
| 80 | SCode.Each ep; | ||
| 81 | SourceInfo i; | ||
| 82 | Option<Absyn.Exp> binding; | ||
| 83 | Option<String> cmt; | ||
| 84 | |||
| 85 | case SCode.MOD(fp, ep, sl, binding, cmt, i) | ||
| 86 | algorithm | ||
| 87 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | binding := if onlyRedeclares then NONE() else constantBindingOrNone(binding); |
| 88 | 20 | sl := removeNonConstantBindingsKeepRedeclaresFromSubMod(sl, onlyRedeclares); | |
| 89 | 20 | then | |
| 90 | SCode.MOD(fp, ep, sl, binding, cmt, i); | ||
| 91 | |||
| 92 | case SCode.REDECL() then inMod; | ||
| 93 | |||
| 94 | else inMod; | ||
| 95 | |||
| 96 | end match; | ||
| 97 | end removeNonConstantBindingsKeepRedeclares; | ||
| 98 | |||
| 99 | protected function removeNonConstantBindingsKeepRedeclaresFromSubMod | ||
| 100 | "@author: adrpo | ||
| 101 | removes the non-constant bindings in submods and keeps the redeclares" | ||
| 102 | input list<SCode.SubMod> inSl; | ||
| 103 | input Boolean onlyRedeclares; | ||
| 104 | output list<SCode.SubMod> outSl; | ||
| 105 | algorithm | ||
| 106 | outSl := match inSl | ||
| 107 | local | ||
| 108 | String n; | ||
| 109 | list<SCode.SubMod> sl,rest; | ||
| 110 | SCode.Mod m; | ||
| 111 | |||
| 112 | case {} then {}; | ||
| 113 | |||
| 114 | case SCode.NAMEMOD(n, m)::rest | ||
| 115 | algorithm | ||
| 116 | 10 | m := removeNonConstantBindingsKeepRedeclares(m, onlyRedeclares); | |
| 117 | 10 | sl := removeNonConstantBindingsKeepRedeclaresFromSubMod(rest, onlyRedeclares); | |
| 118 | 10 | then | |
| 119 | SCode.NAMEMOD(n, m)::sl; | ||
| 120 | |||
| 121 | end match; | ||
| 122 | end removeNonConstantBindingsKeepRedeclaresFromSubMod; | ||
| 123 | |||
| 124 | public function addRedeclareAsElementsToExtends | ||
| 125 | "add the redeclare-as-element elements to extends" | ||
| 126 | input list<SCode.Element> inElements; | ||
| 127 | input list<SCode.Element> redeclareElements; | ||
| 128 | output list<SCode.Element> outExtendsElements; | ||
| 129 | algorithm | ||
| 130 | outExtendsElements := match (inElements, redeclareElements) | ||
| 131 | local | ||
| 132 | SCode.Element el; | ||
| 133 | list<SCode.Element> redecls, rest, out; | ||
| 134 | Absyn.Path baseClassPath; | ||
| 135 | SCode.Visibility visibility; | ||
| 136 | SCode.Mod mod; | ||
| 137 | Option<SCode.Annotation> ann "the extends annotation"; | ||
| 138 | SourceInfo info; | ||
| 139 | SCode.Mod redeclareMod; | ||
| 140 | list<SCode.SubMod> submods; | ||
| 141 | |||
| 142 | // empty, return the same | ||
| 143 | case (_, {}) then inElements; | ||
| 144 | |||
| 145 | // empty elements | ||
| 146 | case ({}, _) then {}; | ||
| 147 | |||
| 148 | // we got some | ||
| 149 | case (SCode.EXTENDS(baseClassPath, visibility, mod, ann, info)::rest, redecls) | ||
| 150 | algorithm | ||
| 151 | 411 | submods := makeElementsIntoSubMods(SCode.NOT_FINAL(), SCode.NOT_EACH(), redecls); | |
| 152 | 411 | redeclareMod := SCode.MOD(SCode.NOT_FINAL(), SCode.NOT_EACH(), submods, NONE(), NONE(), info); | |
| 153 | 411 | mod := SCodeUtil.mergeSCodeMods(redeclareMod, mod); | |
| 154 | 411 | out := addRedeclareAsElementsToExtends(rest, redecls); | |
| 155 | 411 | then | |
| 156 | SCode.EXTENDS(baseClassPath, visibility, mod, ann, info)::out; | ||
| 157 | |||
| 158 | // ignore non-extends | ||
| 159 | case (el::rest, redecls) | ||
| 160 | algorithm | ||
| 161 | 8811 | out := addRedeclareAsElementsToExtends(rest, redecls); | |
| 162 | then | ||
| 163 | el::out; | ||
| 164 | |||
| 165 | end match; | ||
| 166 | end addRedeclareAsElementsToExtends; | ||
| 167 | |||
| 168 | protected function makeElementsIntoSubMods | ||
| 169 | "transform elements into submods with named mods" | ||
| 170 | input SCode.Final inFinal; | ||
| 171 | input SCode.Each inEach; | ||
| 172 | input list<SCode.Element> inElements; | ||
| 173 | output list<SCode.SubMod> outSubMods; | ||
| 174 | algorithm | ||
| 175 | outSubMods := match (inFinal, inEach, inElements) | ||
| 176 | local | ||
| 177 | SCode.Element el; | ||
| 178 | list<SCode.Element> rest; | ||
| 179 | SCode.Final f; | ||
| 180 | SCode.Each e; | ||
| 181 | SCode.Ident n; | ||
| 182 | list<SCode.SubMod> newSubMods; | ||
| 183 | |||
| 184 | // empty | ||
| 185 | case (_, _, {}) then {}; | ||
| 186 | |||
| 187 | // class extends, error! | ||
| 188 | case (f, e, (el as SCode.CLASS(classDef = SCode.CLASS_EXTENDS()))::rest) | ||
| 189 | algorithm | ||
| 190 | // print an error here | ||
| 191 | ✗ | print("- AbsynToSCode.makeElementsIntoSubMods ignoring class-extends redeclare-as-element: " + SCodeDump.unparseElementStr(el,SCodeDump.defaultOptions) + "\n"); | |
| 192 | // recurse | ||
| 193 | ✗ | newSubMods := makeElementsIntoSubMods(f, e, rest); | |
| 194 | then | ||
| 195 | newSubMods; | ||
| 196 | |||
| 197 | // component | ||
| 198 | case (f, e, (el as SCode.COMPONENT(name = n))::rest) | ||
| 199 | algorithm | ||
| 200 | // recurse | ||
| 201 | ✗ | newSubMods := makeElementsIntoSubMods(f, e, rest); | |
| 202 | ✗ | then | |
| 203 | SCode.NAMEMOD(n,SCode.REDECL(f,e,el))::newSubMods; | ||
| 204 | |||
| 205 | // class | ||
| 206 | case (f, e, (el as SCode.CLASS(name = n))::rest) | ||
| 207 | algorithm | ||
| 208 | // recurse | ||
| 209 | 3559 | newSubMods := makeElementsIntoSubMods(f, e, rest); | |
| 210 | 3559 | then | |
| 211 | SCode.NAMEMOD(n,SCode.REDECL(f,e,el))::newSubMods; | ||
| 212 | |||
| 213 | // rest | ||
| 214 | case (f, e, el::rest) | ||
| 215 | algorithm | ||
| 216 | // print an error here | ||
| 217 | ✗ | print("- AbsynToSCode.makeElementsIntoSubMods ignoring redeclare-as-element redeclaration: " + SCodeDump.unparseElementStr(el,SCodeDump.defaultOptions) + "\n"); | |
| 218 | // recurse | ||
| 219 | ✗ | newSubMods := makeElementsIntoSubMods(f, e, rest); | |
| 220 | then | ||
| 221 | newSubMods; | ||
| 222 | end match; | ||
| 223 | end makeElementsIntoSubMods; | ||
| 224 | |||
| 225 | protected function removeReferenceInBinding | ||
| 226 | "@author: adrpo | ||
| 227 | remove the binding that contains a cref" | ||
| 228 | input Option<Absyn.Exp> inBinding; | ||
| 229 | input Absyn.ComponentRef inCref; | ||
| 230 | output Option<Absyn.Exp> outBinding; | ||
| 231 | algorithm | ||
| 232 | outBinding := match inBinding | ||
| 233 | local | ||
| 234 | Absyn.Exp e; | ||
| 235 | list<Absyn.ComponentRef> crlst1, crlst2; | ||
| 236 | |||
| 237 | // if cref is not present keep the binding! | ||
| 238 | case SOME(e) | ||
| 239 | algorithm | ||
| 240 | 24867 | crlst1 := AbsynUtil.getCrefFromExp(e, true, true); | |
| 241 | 24867 | crlst2 := AbsynUtil.removeCrefFromCrefs(crlst1, inCref); | |
| 242 |
2/2✓ Branch 2 taken 2496 times.
✓ Branch 3 taken 22371 times.
|
24867 | then if intEq(listLength(crlst1), listLength(crlst2)) then inBinding else NONE(); |
| 243 | // else | ||
| 244 | else NONE(); | ||
| 245 | end match; | ||
| 246 | end removeReferenceInBinding; | ||
| 247 | |||
| 248 | public function removeSelfReferenceFromMod | ||
| 249 | "@author: adrpo | ||
| 250 | remove the self reference from mod!" | ||
| 251 | input SCode.Mod inMod; | ||
| 252 | input Absyn.ComponentRef inCref; | ||
| 253 | output SCode.Mod outMod; | ||
| 254 | algorithm | ||
| 255 | outMod := match inMod | ||
| 256 | local | ||
| 257 | list<SCode.SubMod> sl; | ||
| 258 | SCode.Final fp; | ||
| 259 | SCode.Each ep; | ||
| 260 | SourceInfo i; | ||
| 261 | Option<Absyn.Exp> binding; | ||
| 262 | Option<String> cmt; | ||
| 263 | |||
| 264 | case SCode.MOD(fp, ep, sl, binding, cmt, i) | ||
| 265 | algorithm | ||
| 266 | 27352 | binding := removeReferenceInBinding(binding, inCref); | |
| 267 | 27352 | sl := removeSelfReferenceFromSubMod(sl, inCref); | |
| 268 | 27352 | then | |
| 269 | SCode.MOD(fp, ep, sl, binding, cmt, i); | ||
| 270 | |||
| 271 | case SCode.REDECL() then inMod; | ||
| 272 | |||
| 273 | else inMod; | ||
| 274 | |||
| 275 | end match; | ||
| 276 | end removeSelfReferenceFromMod; | ||
| 277 | |||
| 278 | protected function removeSelfReferenceFromSubMod | ||
| 279 | "@author: adrpo | ||
| 280 | removes the self references from a submod" | ||
| 281 | input list<SCode.SubMod> inSl; | ||
| 282 | input Absyn.ComponentRef inCref; | ||
| 283 | output list<SCode.SubMod> outSl; | ||
| 284 | algorithm | ||
| 285 | outSl := match inSl | ||
| 286 | local | ||
| 287 | String n; | ||
| 288 | list<SCode.SubMod> sl,rest; | ||
| 289 | SCode.Mod m; | ||
| 290 | |||
| 291 | case {} then {}; | ||
| 292 | |||
| 293 | case SCode.NAMEMOD(n, m)::rest | ||
| 294 | algorithm | ||
| 295 | 24857 | m := removeSelfReferenceFromMod(m, inCref); | |
| 296 | 24857 | sl := removeSelfReferenceFromSubMod(rest, inCref); | |
| 297 | 24857 | then | |
| 298 | SCode.NAMEMOD(n, m)::sl; | ||
| 299 | |||
| 300 | end match; | ||
| 301 | end removeSelfReferenceFromSubMod; | ||
| 302 | |||
| 303 | protected function expandEnumerationSubMod | ||
| 304 | input SCode.SubMod inSubMod; | ||
| 305 | input Boolean inChanged; | ||
| 306 | output SCode.SubMod outSubMod; | ||
| 307 | output Boolean outChanged; | ||
| 308 | algorithm | ||
| 309 | (outSubMod, outChanged) := match inSubMod | ||
| 310 | local | ||
| 311 | SCode.Mod mod, mod1; | ||
| 312 | SCode.Ident ident; | ||
| 313 | case SCode.NAMEMOD(ident=ident, mod=mod) | ||
| 314 | algorithm | ||
| 315 | 986338 | mod1 := expandEnumerationMod(mod); | |
| 316 |
3/4✓ Branch 0 taken 986337 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 986337 times.
✗ Branch 3 not taken.
|
1972675 | then |
| 317 | if referenceEq(mod, mod1) then (inSubMod, inChanged) else (SCode.NAMEMOD(ident, mod1), true); | ||
| 318 | ✗ | else | |
| 319 | (inSubMod, inChanged); | ||
| 320 | end match; | ||
| 321 | end expandEnumerationSubMod; | ||
| 322 | |||
| 323 | public function expandEnumerationMod | ||
| 324 | input SCode.Mod inMod; | ||
| 325 | output SCode.Mod outMod; | ||
| 326 | protected | ||
| 327 | SCode.Final f; | ||
| 328 | SCode.Each e; | ||
| 329 | SCode.Element el, el1; | ||
| 330 | list<SCode.SubMod> submod; | ||
| 331 | Option<Absyn.Exp> binding; | ||
| 332 | SourceInfo info; | ||
| 333 | Boolean changed; | ||
| 334 | Option<String> cmt; | ||
| 335 | algorithm | ||
| 336 | outMod := match inMod | ||
| 337 | case SCode.REDECL(f, e, el) | ||
| 338 | algorithm | ||
| 339 | 637 | el1 := expandEnumerationClass(el); | |
| 340 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 636 times.
|
637 | then |
| 341 | if referenceEq(el, el1) then inMod else SCode.REDECL(f, e, el1); | ||
| 342 | |||
| 343 | case SCode.MOD(f, e, submod, binding, cmt, info) | ||
| 344 | algorithm | ||
| 345 | 2532294 | (submod, changed) := List.mapFold(submod, expandEnumerationSubMod, false); | |
| 346 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2532293 times.
|
2532294 | then if changed then SCode.MOD(f, e, submod, binding, cmt, info) else inMod; |
| 347 | |||
| 348 | else inMod; | ||
| 349 | end match; | ||
| 350 | end expandEnumerationMod; | ||
| 351 | |||
| 352 | public function expandEnumerationClass | ||
| 353 | "@author: PA, adrpo | ||
| 354 | this function expands the enumeration from a list into a class with components | ||
| 355 | if the class is not an enumeration is kept as it is" | ||
| 356 | input SCode.Element inElement; | ||
| 357 | output SCode.Element outElement; | ||
| 358 | algorithm | ||
| 359 | outElement := match inElement | ||
| 360 | local | ||
| 361 | SCode.Ident n; | ||
| 362 | list<SCode.Enum> l; | ||
| 363 | SCode.Comment cmt; | ||
| 364 | SourceInfo info; | ||
| 365 | SCode.Element c; | ||
| 366 | SCode.Prefixes prefixes; | ||
| 367 | SCode.Mod m, m1; | ||
| 368 | Absyn.Path p; | ||
| 369 | SCode.Visibility v; | ||
| 370 | Option<SCode.Annotation> ann; | ||
| 371 | |||
| 372 | case SCode.CLASS(name = n,restriction = SCode.R_TYPE(), prefixes = prefixes, | ||
| 373 | classDef = SCode.ENUMERATION(enumLst=l),cmt=cmt,info = info) | ||
| 374 | algorithm | ||
| 375 | 188040 | c := expandEnumeration(n, l, prefixes, cmt, info); | |
| 376 | then | ||
| 377 | c; | ||
| 378 | |||
| 379 | case SCode.EXTENDS(baseClassPath = p, visibility = v, modifications = m, ann = ann, info = info) | ||
| 380 | algorithm | ||
| 381 | |||
| 382 | 32720 | m1 := expandEnumerationMod(m); | |
| 383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32720 times.
|
32720 | then |
| 384 | if referenceEq(m, m1) then inElement else SCode.EXTENDS(p, v, m1, ann, info); | ||
| 385 | |||
| 386 | else inElement; | ||
| 387 | |||
| 388 | end match; | ||
| 389 | end expandEnumerationClass; | ||
| 390 | |||
| 391 | public function expandEnumeration | ||
| 392 | "author: PA | ||
| 393 | This function takes an Ident and list of strings, and returns an enumeration class." | ||
| 394 | input SCode.Ident n; | ||
| 395 | input list<SCode.Enum> l; | ||
| 396 | input SCode.Prefixes prefixes; | ||
| 397 | input SCode.Comment cmt; | ||
| 398 | input SourceInfo info; | ||
| 399 | output SCode.Element outClass; | ||
| 400 | algorithm | ||
| 401 | 188040 | outClass := | |
| 402 | SCode.CLASS( | ||
| 403 | n, | ||
| 404 | prefixes, | ||
| 405 | SCode.NOT_ENCAPSULATED(), | ||
| 406 | SCode.NOT_PARTIAL(), | ||
| 407 | SCode.R_ENUMERATION(), | ||
| 408 | makeEnumParts(l, info), | ||
| 409 | cmt, | ||
| 410 | info); | ||
| 411 | end expandEnumeration; | ||
| 412 | |||
| 413 | protected function makeEnumParts | ||
| 414 | input list<SCode.Enum> inEnumLst; | ||
| 415 | input SourceInfo info; | ||
| 416 | output SCode.ClassDef classDef; | ||
| 417 | algorithm | ||
| 418 | 188040 | classDef := SCode.PARTS(makeEnumComponents(inEnumLst, info),{},{},{},{},{},{},NONE()); | |
| 419 | end makeEnumParts; | ||
| 420 | |||
| 421 | protected function makeEnumComponents | ||
| 422 | "Translates a list of Enums to a list of elements of type EnumType." | ||
| 423 | input list<SCode.Enum> inEnumLst; | ||
| 424 | input SourceInfo info; | ||
| 425 | output list<SCode.Element> outSCodeElementLst; | ||
| 426 | algorithm | ||
| 427 |
4/4✓ Branch 0 taken 898634 times.
✓ Branch 1 taken 188040 times.
✓ Branch 2 taken 898634 times.
✓ Branch 3 taken 188040 times.
|
1086674 | outSCodeElementLst := list(SCodeUtil.makeEnumType(e,info) for e in inEnumLst); |
| 428 | end makeEnumComponents; | ||
| 429 | |||
| 430 | annotation(__OpenModelica_Interface="frontend_inst"); | ||
| 431 | end SCodeInstUtil; | ||
| 432 |