OMCompiler/Compiler/NFFrontEnd/NFExpressionIterator.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 NFExpressionIterator | ||
| 37 | protected | ||
| 38 | import ExpressionIterator = NFExpressionIterator; | ||
| 39 | import ComponentRef = NFComponentRef; | ||
| 40 | import NFInstNode.InstNode; | ||
| 41 | import ExpandExp = NFExpandExp; | ||
| 42 | import SimplifyExp = NFSimplifyExp; | ||
| 43 | import MetaModelica.Dangerous.listReverseInPlace; | ||
| 44 | import Array; | ||
| 45 | |||
| 46 | public | ||
| 47 | import Expression = NFExpression; | ||
| 48 | import Binding = NFBinding; | ||
| 49 | import Util; | ||
| 50 | |||
| 51 | record ARRAY_ITERATOR | ||
| 52 | array<Expression> arr; | ||
| 53 | Integer index; | ||
| 54 | list<array<Expression>> arrays; | ||
| 55 | end ARRAY_ITERATOR; | ||
| 56 | |||
| 57 | record SCALAR_ITERATOR | ||
| 58 | Expression exp; | ||
| 59 | end SCALAR_ITERATOR; | ||
| 60 | |||
| 61 | record EACH_ITERATOR | ||
| 62 | Expression exp; | ||
| 63 | end EACH_ITERATOR; | ||
| 64 | |||
| 65 | record NONE_ITERATOR | ||
| 66 | end NONE_ITERATOR; | ||
| 67 | |||
| 68 | function toString | ||
| 69 | input ExpressionIterator iter; | ||
| 70 | output String str; | ||
| 71 | algorithm | ||
| 72 | str := match iter | ||
| 73 | case ARRAY_ITERATOR() | ||
| 74 | ✗ | then List.toStringCustom(iter.arrays, function Array.toString( | |
| 75 | inPrintFunc = Expression.toString, | ||
| 76 | inNameStr = "", | ||
| 77 | inBeginStr = "{", | ||
| 78 | inDelimitStr = ", ", | ||
| 79 | inEndStr = "}", | ||
| 80 | inPrintEmpty = false, | ||
| 81 | maxLength = 0), "[ARRY] array iterator:\n", "", "\n", ""); | ||
| 82 | |||
| 83 | ✗ | case SCALAR_ITERATOR() then "[SCAL] scalar iterator: " + Expression.toString(iter.exp) + "\n"; | |
| 84 | ✗ | case EACH_ITERATOR() then "[EACH] each iterator: " + Expression.toString(iter.exp) + "\n"; | |
| 85 | case NONE_ITERATOR() then "[NONE] no iterator.\n"; | ||
| 86 | end match; | ||
| 87 | end toString; | ||
| 88 | |||
| 89 | |||
| 90 | function fromExp | ||
| 91 | input Expression exp; | ||
| 92 | input Boolean backend = false; | ||
| 93 | input Boolean resize = false; | ||
| 94 | output ExpressionIterator iterator; | ||
| 95 | algorithm | ||
| 96 | iterator := match exp | ||
| 97 | local | ||
| 98 | Expression e; | ||
| 99 | Boolean expanded; | ||
| 100 | |||
| 101 | case Expression.ARRAY() | ||
| 102 | algorithm | ||
| 103 | 96428 | (e, expanded) := ExpandExp.expand(exp, backend, resize); | |
| 104 | |||
| 105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96428 times.
|
96428 | if not expanded then |
| 106 | ✗ | Error.terminate(getInstanceName() + " got unexpandable expression `" + | |
| 107 | Expression.toString(exp) + "`", sourceInfo()); | ||
| 108 | end if; | ||
| 109 | 96428 | then | |
| 110 | makeArrayIterator(e); | ||
| 111 | |||
| 112 | case Expression.CREF() | ||
| 113 | algorithm | ||
| 114 | 8825 | e := ExpandExp.expandCref(exp, backend); | |
| 115 | |||
| 116 | iterator := match e | ||
| 117 | 8825 | case Expression.ARRAY() then fromExp(e, backend, resize); | |
| 118 | ✗ | else SCALAR_ITERATOR(e); | |
| 119 | end match; | ||
| 120 | then | ||
| 121 | iterator; | ||
| 122 | |||
| 123 | else | ||
| 124 | algorithm | ||
| 125 | 5273 | (e, expanded) := ExpandExp.expand(exp, backend, resize); | |
| 126 |
3/4✓ Branch 0 taken 5273 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 102 times.
✓ Branch 4 taken 5171 times.
|
5273 | then |
| 127 | if expanded then | ||
| 128 | (if Expression.isEqual(e, exp) then SCALAR_ITERATOR(exp) else fromExp(e, backend, resize)) else | ||
| 129 | NONE_ITERATOR(); | ||
| 130 | |||
| 131 | end match; | ||
| 132 | end fromExp; | ||
| 133 | |||
| 134 | function fromExpOpt | ||
| 135 | input Option<Expression> optExp; | ||
| 136 | output ExpressionIterator iterator; | ||
| 137 | algorithm | ||
| 138 | iterator := match optExp | ||
| 139 | local | ||
| 140 | Expression exp; | ||
| 141 | |||
| 142 | 2640 | case SOME(exp) then fromExp(exp); | |
| 143 | else NONE_ITERATOR(); | ||
| 144 | end match; | ||
| 145 | end fromExpOpt; | ||
| 146 | |||
| 147 | function fromBinding | ||
| 148 | input Binding binding; | ||
| 149 | output ExpressionIterator iterator; | ||
| 150 | algorithm | ||
| 151 | iterator := match binding | ||
| 152 | local | ||
| 153 | |||
| 154 | case Binding.TYPED_BINDING(eachType = NFBinding.EachType.EACH) | ||
| 155 | 9945 | then EACH_ITERATOR(binding.bindingExp); | |
| 156 | |||
| 157 | case Binding.TYPED_BINDING() | ||
| 158 | 68254 | then fromExp(binding.bindingExp); | |
| 159 | |||
| 160 | case Binding.FLAT_BINDING() | ||
| 161 | 105 | then EACH_ITERATOR(binding.bindingExp); | |
| 162 | end match; | ||
| 163 | end fromBinding; | ||
| 164 | |||
| 165 | function isUniform | ||
| 166 | "Whether every element the iterator yields is the same expression object, | ||
| 167 | so one element stands for all of them." | ||
| 168 | input ExpressionIterator iterator; | ||
| 169 | output Boolean uniform; | ||
| 170 | algorithm | ||
| 171 | uniform := match iterator | ||
| 172 | 1961 | case ARRAY_ITERATOR() then isUniformArrays(iterator.arr :: iterator.arrays); | |
| 173 | case EACH_ITERATOR() then true; | ||
| 174 | case NONE_ITERATOR() then true; | ||
| 175 | else false; | ||
| 176 | end match; | ||
| 177 | end isUniform; | ||
| 178 | |||
| 179 | function isUniformArrays | ||
| 180 | input list<array<Expression>> arrays; | ||
| 181 | output Boolean uniform = true; | ||
| 182 | protected | ||
| 183 | Option<Expression> first = NONE(); | ||
| 184 | algorithm | ||
| 185 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 2296 times.
✓ Branch 2 taken 2296 times.
✓ Branch 3 taken 1744 times.
|
4040 | for arr in arrays loop |
| 186 |
2/2✓ Branch 1 taken 8314 times.
✓ Branch 2 taken 2079 times.
|
10393 | for e in arr loop |
| 187 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 8314 times.
✓ Branch 2 taken 1961 times.
✓ Branch 3 taken 6353 times.
|
8314 | if isNone(first) then |
| 188 | first := SOME(e); | ||
| 189 | elseif not referenceEq(e, Util.getOption(first)) then | ||
| 190 | uniform := false; | ||
| 191 | 217 | return; | |
| 192 | end if; | ||
| 193 | end for; | ||
| 194 | end for; | ||
| 195 | end isUniformArrays; | ||
| 196 | |||
| 197 | function hasNext | ||
| 198 | input ExpressionIterator iterator; | ||
| 199 | output Boolean hasNext; | ||
| 200 | algorithm | ||
| 201 | hasNext := match iterator | ||
| 202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72522 times.
|
145044 | case ARRAY_ITERATOR() then iterator.index <= arrayLength(iterator.arr); |
| 203 | case SCALAR_ITERATOR() then true; | ||
| 204 | case EACH_ITERATOR() then true; | ||
| 205 | case NONE_ITERATOR() then false; | ||
| 206 | end match; | ||
| 207 | end hasNext; | ||
| 208 | |||
| 209 | function next | ||
| 210 | input output ExpressionIterator iterator; | ||
| 211 | output Expression nextExp; | ||
| 212 | algorithm | ||
| 213 | (iterator, nextExp) := match iterator | ||
| 214 | local | ||
| 215 | list<Expression> rest, arr; | ||
| 216 | Expression next; | ||
| 217 | list<array<Expression>> arrs; | ||
| 218 | |||
| 219 | case ARRAY_ITERATOR() | ||
| 220 | algorithm | ||
| 221 | 316378 | next := arrayGet(iterator.arr, iterator.index); | |
| 222 | |||
| 223 |
2/2✓ Branch 0 taken 100700 times.
✓ Branch 1 taken 215678 times.
|
316378 | if iterator.index >= arrayLength(iterator.arr) then |
| 224 | 100700 | arrs := iterator.arrays; | |
| 225 |
3/4✓ Branch 0 taken 6002 times.
✓ Branch 1 taken 94698 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6002 times.
|
106702 | while not listEmpty(arrs) and arrayEmpty(listHead(arrs)) loop |
| 226 | ✗ | arrs := listRest(arrs); | |
| 227 | end while; | ||
| 228 | |||
| 229 |
2/2✓ Branch 0 taken 94698 times.
✓ Branch 1 taken 6002 times.
|
100700 | if listEmpty(arrs) then |
| 230 | 94698 | iterator := ARRAY_ITERATOR(listArray({}), 1, {}); | |
| 231 | else | ||
| 232 | 6002 | iterator := ARRAY_ITERATOR(listHead(arrs), 1, listRest(arrs)); | |
| 233 | end if; | ||
| 234 | else | ||
| 235 | 215678 | iterator.index := iterator.index + 1; | |
| 236 | end if; | ||
| 237 | then | ||
| 238 | (iterator, next); | ||
| 239 | |||
| 240 | case SCALAR_ITERATOR() | ||
| 241 | 102 | then (NONE_ITERATOR(), iterator.exp); | |
| 242 | |||
| 243 | 37597 | case EACH_ITERATOR() then (iterator, iterator.exp); | |
| 244 | end match; | ||
| 245 | end next; | ||
| 246 | |||
| 247 | function nextOpt | ||
| 248 | input output ExpressionIterator iterator; | ||
| 249 | output Option<Expression> nextExp; | ||
| 250 | protected | ||
| 251 | Expression exp; | ||
| 252 | algorithm | ||
| 253 |
2/2✓ Branch 1 taken 9775 times.
✓ Branch 2 taken 31786 times.
|
41561 | if hasNext(iterator) then |
| 254 | 9775 | (iterator, exp) := next(iterator); | |
| 255 | 9775 | nextExp := SOME(exp); | |
| 256 | else | ||
| 257 | nextExp := NONE(); | ||
| 258 | end if; | ||
| 259 | end nextOpt; | ||
| 260 | |||
| 261 | function toList | ||
| 262 | // TODO: Implement this function more efficiently, using the internal | ||
| 263 | // structure of the iterators instead of hasNext and next. | ||
| 264 | input ExpressionIterator iterator; | ||
| 265 | output list<Expression> expl = {}; | ||
| 266 | protected | ||
| 267 | ExpressionIterator iter; | ||
| 268 | Expression exp; | ||
| 269 | algorithm | ||
| 270 | iter := iterator; | ||
| 271 | |||
| 272 | ✗ | while hasNext(iter) loop | |
| 273 | ✗ | (iter, exp) := next(iter); | |
| 274 | ✗ | expl := exp :: expl; | |
| 275 | end while; | ||
| 276 | |||
| 277 | ✗ | expl := listReverse(expl); | |
| 278 | end toList; | ||
| 279 | |||
| 280 | function isSubscriptedArrayCall | ||
| 281 | "only checks first slice for a subscripted call and assumes it holds for all of them" | ||
| 282 | input ExpressionIterator iterator; | ||
| 283 | input Boolean trySimplify = true; | ||
| 284 | output Boolean b; | ||
| 285 | protected | ||
| 286 | function is_sub_call | ||
| 287 | input Expression exp; | ||
| 288 | input Boolean trySimplify; | ||
| 289 | output Boolean res; | ||
| 290 | algorithm | ||
| 291 | res := match exp | ||
| 292 | case Expression.SUBSCRIPTED_EXP(exp = Expression.CALL()) | ||
| 293 |
2/4✓ Branch 0 taken 322 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 322 times.
✗ Branch 5 not taken.
|
322 | then not trySimplify or Expression.isCall(SimplifyExp.simplify(exp.exp)); |
| 294 | else false; | ||
| 295 | end match; | ||
| 296 | end is_sub_call; | ||
| 297 | algorithm | ||
| 298 | b := match iterator | ||
| 299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8610 times.
|
17220 | case ARRAY_ITERATOR() then is_sub_call(arrayGet(iterator.arr, 1), trySimplify); |
| 300 | else false; | ||
| 301 | end match; | ||
| 302 | end isSubscriptedArrayCall; | ||
| 303 | |||
| 304 | protected | ||
| 305 | function makeArrayIterator | ||
| 306 | input Expression exp; | ||
| 307 | output ExpressionIterator iterator; | ||
| 308 | protected | ||
| 309 | list<array<Expression>> arrays; | ||
| 310 | algorithm | ||
| 311 | 96428 | arrays := flattenArray(exp, {}); | |
| 312 | |||
| 313 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 96423 times.
|
96428 | if listEmpty(arrays) then |
| 314 | 5 | iterator := ARRAY_ITERATOR(listArray({}), 1, arrays); | |
| 315 | else | ||
| 316 | 96423 | iterator := ARRAY_ITERATOR(listHead(arrays), 1, listRest(arrays)); | |
| 317 | end if; | ||
| 318 | end makeArrayIterator; | ||
| 319 | |||
| 320 | function flattenArray | ||
| 321 | input Expression exp; | ||
| 322 | input output list<array<Expression>> arrays; | ||
| 323 | algorithm | ||
| 324 | 96428 | arrays := flattenArray_impl(exp, {}); | |
| 325 | 96428 | arrays := listReverseInPlace(arrays); | |
| 326 | |||
| 327 |
4/4✓ Branch 0 taken 96428 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 96423 times.
✓ Branch 4 taken 5 times.
|
192861 | while not listEmpty(arrays) and arrayEmpty(listHead(arrays)) loop |
| 328 | 5 | arrays := listRest(arrays); | |
| 329 | end while; | ||
| 330 | end flattenArray; | ||
| 331 | |||
| 332 | function flattenArray_impl | ||
| 333 | input Expression exp; | ||
| 334 | input output list<array<Expression>> arrays; | ||
| 335 | algorithm | ||
| 336 |
2/2✓ Branch 1 taken 102940 times.
✓ Branch 2 taken 3487 times.
|
106427 | if Expression.isVector(exp) then |
| 337 | 102940 | arrays := Expression.arrayElements(exp) :: arrays; | |
| 338 | else | ||
| 339 |
2/2✓ Branch 2 taken 9999 times.
✓ Branch 3 taken 3487 times.
|
16973 | for e in Expression.arrayElements(exp) loop |
| 340 | 9999 | arrays := flattenArray_impl(e, arrays); | |
| 341 | end for; | ||
| 342 | end if; | ||
| 343 | end flattenArray_impl; | ||
| 344 | |||
| 345 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 346 | end NFExpressionIterator; | ||
| 347 |