OMCompiler/Compiler/FrontEnd/ExpressionBasics.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 ExpressionBasics | ||
| 37 | " file: ExpressionBasics.mo | ||
| 38 | package: ExpressionBasics | ||
| 39 | description: ExpressionBasics | ||
| 40 | |||
| 41 | |||
| 42 | This file contains the module ExpressionDump, which contains the most basic functions | ||
| 43 | to print and work with DAE.Expression." | ||
| 44 | |||
| 45 | // public imports | ||
| 46 | import DAE; | ||
| 47 | protected | ||
| 48 | import AbsynUtil; | ||
| 49 | import ComponentReferenceBasics; | ||
| 50 | import Error; | ||
| 51 | import ExpressionDumpTpl; | ||
| 52 | import List; | ||
| 53 | import MetaModelica.Dangerous; | ||
| 54 | import Tpl; | ||
| 55 | import Util; | ||
| 56 | |||
| 57 | public function printExpStr | ||
| 58 | "This function prints a complete expression." | ||
| 59 | input DAE.Exp e; | ||
| 60 | output String s; | ||
| 61 | algorithm | ||
| 62 | 1311879 | s := Tpl.tplString2(ExpressionDumpTpl.dumpExp, e, "\""); | |
| 63 | end printExpStr; | ||
| 64 | |||
| 65 | public function dimensionString | ||
| 66 | "Returns a string representation of an array dimension." | ||
| 67 | input DAE.Dimension dim; | ||
| 68 | output String str; | ||
| 69 | algorithm | ||
| 70 | str := match dim | ||
| 71 | local | ||
| 72 | String s; | ||
| 73 | Integer x; | ||
| 74 | Absyn.Path p; | ||
| 75 | DAE.Exp e; | ||
| 76 | case DAE.DIM_UNKNOWN() then ":"; | ||
| 77 | |||
| 78 | case DAE.DIM_ENUM(enumTypeName = p) | ||
| 79 | algorithm | ||
| 80 | 1 | s := AbsynUtil.pathString(p); | |
| 81 | then | ||
| 82 | s; | ||
| 83 | |||
| 84 | case DAE.DIM_BOOLEAN() then "Boolean"; | ||
| 85 | |||
| 86 | case DAE.DIM_INTEGER(integer = x) | ||
| 87 | algorithm | ||
| 88 | 13450 | s := intString(x); | |
| 89 | then | ||
| 90 | s; | ||
| 91 | |||
| 92 | case DAE.DIM_EXP(exp = e) | ||
| 93 | algorithm | ||
| 94 | 4 | s := printExpStr(e); | |
| 95 | then | ||
| 96 | s; | ||
| 97 | end match; | ||
| 98 | end dimensionString; | ||
| 99 | |||
| 100 | public function dimensionsString | ||
| 101 | "Returns a string representation of an array dimension." | ||
| 102 | input DAE.Dimensions dims; | ||
| 103 | output String str; | ||
| 104 | algorithm | ||
| 105 | 20317 | str := stringDelimitList(List.map(dims,dimensionString),","); | |
| 106 | end dimensionsString; | ||
| 107 | |||
| 108 | public function shouldParenthesize | ||
| 109 | "Determines whether an operand in an expression needs parentheses around it." | ||
| 110 | input DAE.Exp inOperand; | ||
| 111 | input DAE.Exp inOperator; | ||
| 112 | input Boolean inLhs; | ||
| 113 | output Boolean outShouldParenthesize; | ||
| 114 | algorithm | ||
| 115 | outShouldParenthesize := match inOperand | ||
| 116 | local | ||
| 117 | Integer diff; | ||
| 118 | |||
| 119 | case DAE.UNARY() then true; | ||
| 120 | |||
| 121 | else | ||
| 122 | algorithm | ||
| 123 | 2622704 | diff := Util.intCompare(priority(inOperand, inLhs), | |
| 124 | priority(inOperator, inLhs)); | ||
| 125 | 2622704 | then | |
| 126 | shouldParenthesize2(diff, inOperand, inLhs); | ||
| 127 | |||
| 128 | end match; | ||
| 129 | end shouldParenthesize; | ||
| 130 | |||
| 131 | protected function shouldParenthesize2 | ||
| 132 | input Integer inPrioDiff; | ||
| 133 | input DAE.Exp inOperand; | ||
| 134 | input Boolean inLhs; | ||
| 135 | output Boolean outShouldParenthesize; | ||
| 136 | algorithm | ||
| 137 | outShouldParenthesize := match inPrioDiff | ||
| 138 | case 1 then true; | ||
| 139 |
2/2✓ Branch 0 taken 81832 times.
✓ Branch 1 taken 124424 times.
|
206256 | case 0 then if inLhs then isNonAssociativeExp(inOperand) else |
| 140 | not isAssociativeExp(inOperand); | ||
| 141 | else false; | ||
| 142 | end match; | ||
| 143 | end shouldParenthesize2; | ||
| 144 | |||
| 145 | protected function isAssociativeExp | ||
| 146 | "Determines whether the given expression represents an associative operation or not." | ||
| 147 | input DAE.Exp inExp; | ||
| 148 | output Boolean outIsAssociative; | ||
| 149 | algorithm | ||
| 150 | outIsAssociative := match inExp | ||
| 151 | local | ||
| 152 | DAE.Operator op; | ||
| 153 | |||
| 154 | 124365 | case DAE.BINARY(operator = op) then isAssociativeOp(op); | |
| 155 | case DAE.LBINARY() then true; | ||
| 156 | else false; | ||
| 157 | end match; | ||
| 158 | end isAssociativeExp; | ||
| 159 | |||
| 160 | protected function isAssociativeOp | ||
| 161 | "Determines whether the given operator is associative or not." | ||
| 162 | input DAE.Operator inOperator; | ||
| 163 | output Boolean outIsAssociative; | ||
| 164 | algorithm | ||
| 165 | outIsAssociative := match inOperator | ||
| 166 | case DAE.ADD() then true; | ||
| 167 | case DAE.MUL() then true; | ||
| 168 | case DAE.ADD_ARR() then true; | ||
| 169 | case DAE.MUL_ARRAY_SCALAR() then true; | ||
| 170 | case DAE.ADD_ARRAY_SCALAR() then true; | ||
| 171 | else false; | ||
| 172 | end match; | ||
| 173 | end isAssociativeOp; | ||
| 174 | |||
| 175 | protected function isNonAssociativeExp | ||
| 176 | input DAE.Exp exp; | ||
| 177 | output Boolean isNonAssociative; | ||
| 178 | algorithm | ||
| 179 | isNonAssociative := match exp | ||
| 180 | 75764 | case DAE.BINARY() then isNonAssociativeOp(exp.operator); | |
| 181 | else false; | ||
| 182 | end match; | ||
| 183 | end isNonAssociativeExp; | ||
| 184 | |||
| 185 | protected function isNonAssociativeOp | ||
| 186 | input DAE.Operator inOperator; | ||
| 187 | output Boolean isNonAssociative; | ||
| 188 | algorithm | ||
| 189 | isNonAssociative := match inOperator | ||
| 190 | case DAE.POW() then true; | ||
| 191 | case DAE.POW_ARRAY_SCALAR() then true; | ||
| 192 | case DAE.POW_SCALAR_ARRAY() then true; | ||
| 193 | case DAE.POW_ARR() then true; | ||
| 194 | case DAE.POW_ARR2() then true; | ||
| 195 | else false; | ||
| 196 | end match; | ||
| 197 | end isNonAssociativeOp; | ||
| 198 | |||
| 199 | public function priority | ||
| 200 | "Returns an integer priority given an expression, which is used by | ||
| 201 | ExpressionDumpTpl to add parentheses when dumping expressions. The inLhs | ||
| 202 | argument should be true if the expression occurs on the left side of a binary | ||
| 203 | operation, otherwise false. This is because we don't need to add parentheses | ||
| 204 | to expressions such as x * y / z, but x / (y * z) needs them, so the | ||
| 205 | priorities of some binary operations differ depending on which side they are." | ||
| 206 | input DAE.Exp inExp; | ||
| 207 | input Boolean inLhs; | ||
| 208 | output Integer outPriority; | ||
| 209 | algorithm | ||
| 210 | outPriority := match(inExp, inLhs) | ||
| 211 | local | ||
| 212 | DAE.Operator op; | ||
| 213 | |||
| 214 | 1500676 | case (DAE.BINARY(operator = op), false) then priorityBinopRhs(op); | |
| 215 | 1344230 | case (DAE.BINARY(operator = op), true) then priorityBinopLhs(op); | |
| 216 | case (DAE.RCONST(), _) guard inExp.real < 0.0 then 4; // Same as unary minus of a real literal | ||
| 217 | case (DAE.UNARY(), _) then 4; | ||
| 218 | 121211 | case (DAE.LBINARY(operator = op), _) then priorityLBinop(op); | |
| 219 | case (DAE.LUNARY(), _) then 7; | ||
| 220 | case (DAE.RELATION(), _) then 6; | ||
| 221 | case (DAE.RANGE(), _) then 10; | ||
| 222 | case (DAE.IFEXP(), _) then 11; | ||
| 223 | else 0; | ||
| 224 | end match; | ||
| 225 | end priority; | ||
| 226 | |||
| 227 | protected function priorityBinopLhs | ||
| 228 | "Returns the priority for a binary operation on the left hand side. Add and | ||
| 229 | sub has the same priority, and mul and div too, in contrast with | ||
| 230 | priorityBinopRhs." | ||
| 231 | input DAE.Operator inOp; | ||
| 232 | output Integer outPriority; | ||
| 233 | algorithm | ||
| 234 | outPriority := match inOp | ||
| 235 | case DAE.ADD() then 5; | ||
| 236 | case DAE.SUB() then 5; | ||
| 237 | case DAE.MUL() then 2; | ||
| 238 | case DAE.DIV() then 2; | ||
| 239 | case DAE.POW() then 1; | ||
| 240 | case DAE.ADD_ARR() then 5; | ||
| 241 | case DAE.SUB_ARR() then 5; | ||
| 242 | case DAE.MUL_ARR() then 2; | ||
| 243 | case DAE.DIV_ARR() then 2; | ||
| 244 | case DAE.MUL_ARRAY_SCALAR() then 2; | ||
| 245 | case DAE.ADD_ARRAY_SCALAR() then 5; | ||
| 246 | case DAE.SUB_SCALAR_ARRAY() then 5; | ||
| 247 | case DAE.MUL_SCALAR_PRODUCT() then 2; | ||
| 248 | case DAE.MUL_MATRIX_PRODUCT() then 2; | ||
| 249 | case DAE.DIV_ARRAY_SCALAR() then 2; | ||
| 250 | case DAE.DIV_SCALAR_ARRAY() then 2; | ||
| 251 | case DAE.POW_ARRAY_SCALAR() then 1; | ||
| 252 | case DAE.POW_SCALAR_ARRAY() then 1; | ||
| 253 | case DAE.POW_ARR() then 1; | ||
| 254 | case DAE.POW_ARR2() then 1; | ||
| 255 | end match; | ||
| 256 | end priorityBinopLhs; | ||
| 257 | |||
| 258 | protected function priorityBinopRhs | ||
| 259 | "Returns the priority for a binary operation on the right hand side. Add and | ||
| 260 | sub has different priorities, and mul and div too, in contrast with | ||
| 261 | priorityBinopLhs." | ||
| 262 | input DAE.Operator inOp; | ||
| 263 | output Integer outPriority; | ||
| 264 | algorithm | ||
| 265 | outPriority := match inOp | ||
| 266 | case DAE.ADD() then 6; | ||
| 267 | case DAE.SUB() then 5; | ||
| 268 | case DAE.MUL() then 3; | ||
| 269 | case DAE.DIV() then 2; | ||
| 270 | case DAE.POW() then 1; | ||
| 271 | case DAE.ADD_ARR() then 6; | ||
| 272 | case DAE.SUB_ARR() then 5; | ||
| 273 | case DAE.MUL_ARR() then 3; | ||
| 274 | case DAE.DIV_ARR() then 2; | ||
| 275 | case DAE.MUL_ARRAY_SCALAR() then 3; | ||
| 276 | case DAE.ADD_ARRAY_SCALAR() then 6; | ||
| 277 | case DAE.SUB_SCALAR_ARRAY() then 5; | ||
| 278 | case DAE.MUL_SCALAR_PRODUCT() then 3; | ||
| 279 | case DAE.MUL_MATRIX_PRODUCT() then 3; | ||
| 280 | case DAE.DIV_ARRAY_SCALAR() then 2; | ||
| 281 | case DAE.DIV_SCALAR_ARRAY() then 2; | ||
| 282 | case DAE.POW_ARRAY_SCALAR() then 1; | ||
| 283 | case DAE.POW_SCALAR_ARRAY() then 1; | ||
| 284 | case DAE.POW_ARR() then 1; | ||
| 285 | case DAE.POW_ARR2() then 1; | ||
| 286 | end match; | ||
| 287 | end priorityBinopRhs; | ||
| 288 | |||
| 289 | protected function priorityLBinop | ||
| 290 | input DAE.Operator inOp; | ||
| 291 | output Integer outPriority; | ||
| 292 | algorithm | ||
| 293 | outPriority := match inOp | ||
| 294 | case DAE.AND() then 8; | ||
| 295 | case DAE.OR() then 9; | ||
| 296 | end match; | ||
| 297 | end priorityLBinop; | ||
| 298 | |||
| 299 | public function evalCat<Exp> | ||
| 300 | input Integer dim; | ||
| 301 | input list<Exp> exps; | ||
| 302 | input GetArrayContents getArrayContents; | ||
| 303 | input ToString toString; | ||
| 304 | output list<Exp> outExps; | ||
| 305 | output list<Integer> outDims; | ||
| 306 | partial function GetArrayContents | ||
| 307 | input Exp e; | ||
| 308 | output list<Exp> es; | ||
| 309 | end GetArrayContents; | ||
| 310 | partial function MakeArrayFromList | ||
| 311 | input list<Exp> es; | ||
| 312 | output Exp e; | ||
| 313 | end MakeArrayFromList; | ||
| 314 | partial function ToString | ||
| 315 | input Exp e; | ||
| 316 | output String s; | ||
| 317 | end ToString; | ||
| 318 | protected | ||
| 319 | list<Exp> arr; | ||
| 320 | list<list<Exp>> arrs={}; | ||
| 321 | list<Integer> dims, firstDims={}, lastDims, reverseDims; | ||
| 322 | list<list<Integer>> dimsLst={}; | ||
| 323 | Integer j, k, l, thisDim, lastDim; | ||
| 324 | array<Exp> expArr; | ||
| 325 | algorithm | ||
| 326 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10111 times.
|
10111 | true := dim >= 1; |
| 327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10111 times.
|
10111 | false := listEmpty(exps); |
| 328 |
2/2✓ Branch 0 taken 3435 times.
✓ Branch 1 taken 6676 times.
|
10111 | if 1 == dim then |
| 329 |
5/6✓ Branch 1 taken 9272 times.
✓ Branch 2 taken 3120 times.
✓ Branch 3 taken 9272 times.
✓ Branch 4 taken 3120 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9272 times.
|
12392 | outExps := listAppend(getArrayContents(e) for e in listReverse(exps)); |
| 330 | 3120 | outDims := {listLength(outExps)}; | |
| 331 | 3120 | return; | |
| 332 | end if; | ||
| 333 |
2/2✓ Branch 1 taken 20113 times.
✓ Branch 2 taken 6668 times.
|
26781 | for e in listReverse(exps) loop |
| 334 | // Here we get a linear representation of all expressions in the array | ||
| 335 | // and the dimensions necessary to build up the array again | ||
| 336 | 20113 | (arr,dims) := evalCatGetFlatArray(e, dim, getArrayContents=getArrayContents, toString=toString); | |
| 337 | arrs := arr::arrs; | ||
| 338 | 20105 | dimsLst := dims::dimsLst; | |
| 339 | end for; | ||
| 340 | 6668 | for i in 1:(dim-1) loop | |
| 341 |
4/4✓ Branch 0 taken 20108 times.
✓ Branch 1 taken 6669 times.
✓ Branch 2 taken 20108 times.
✓ Branch 3 taken 6669 times.
|
26777 | j := min(listHead(d) for d in dimsLst); |
| 342 | |||
| 343 |
5/6✓ Branch 0 taken 20108 times.
✓ Branch 1 taken 6669 times.
✓ Branch 2 taken 20108 times.
✓ Branch 3 taken 6669 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6669 times.
|
26777 | if j <> max(listHead(d) for d in dimsLst) then |
| 344 | ✗ | Error.terminate(getInstanceName() + ": cat got uneven dimensions for dim=" + String(i) + " " + stringDelimitList(list(toString(e) for e in exps), ", "), sourceInfo()); | |
| 345 | end if; | ||
| 346 | |||
| 347 | firstDims := j :: firstDims; | ||
| 348 |
4/4✓ Branch 0 taken 20108 times.
✓ Branch 1 taken 6669 times.
✓ Branch 2 taken 20108 times.
✓ Branch 3 taken 6669 times.
|
26777 | dimsLst := list(listRest(d) for d in dimsLst); |
| 349 | end for; | ||
| 350 | reverseDims := firstDims; | ||
| 351 | 6668 | firstDims := listReverse(firstDims); | |
| 352 |
4/4✓ Branch 0 taken 20105 times.
✓ Branch 1 taken 6668 times.
✓ Branch 2 taken 20105 times.
✓ Branch 3 taken 6668 times.
|
26773 | lastDims := list(listHead(d) for d in dimsLst); |
| 353 |
4/4✓ Branch 0 taken 20105 times.
✓ Branch 1 taken 6668 times.
✓ Branch 2 taken 20105 times.
✓ Branch 3 taken 6668 times.
|
26773 | lastDim := sum(d for d in lastDims); |
| 354 | reverseDims := lastDim::reverseDims; | ||
| 355 | // Fill in the elements of the new array in the new order; this uses | ||
| 356 | // an array structure for random access | ||
| 357 |
4/4✓ Branch 0 taken 6669 times.
✓ Branch 1 taken 6668 times.
✓ Branch 2 taken 6669 times.
✓ Branch 3 taken 6668 times.
|
13337 | expArr := Dangerous.arrayCreateNoInit(lastDim*product(d for d in firstDims), listHead(exps)); |
| 358 | k := 1; | ||
| 359 |
2/2✓ Branch 0 taken 20105 times.
✓ Branch 1 taken 6668 times.
|
26773 | for exps in arrs loop |
| 360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20105 times.
|
20105 | thisDim :: lastDims := lastDims; |
| 361 | l := 0; | ||
| 362 |
2/2✓ Branch 0 taken 20914 times.
✓ Branch 1 taken 20105 times.
|
41019 | for e in exps loop |
| 363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20914 times.
|
41828 | arrayUpdate(expArr, k+mod(l, thisDim)+(lastDim*div(l, thisDim)), e); |
| 364 | 20914 | l := l+1; | |
| 365 | end for; | ||
| 366 | 20105 | k := k + thisDim; | |
| 367 | end for; | ||
| 368 | // Convert the flat array structure to a tree array structure with the | ||
| 369 | // correct dimensions | ||
| 370 | 6668 | outExps := arrayList(expArr); | |
| 371 | 6668 | outDims := listReverse(reverseDims); | |
| 372 | end evalCat; | ||
| 373 | |||
| 374 | protected function evalCatGetFlatArray<Exp> | ||
| 375 | input Exp e; | ||
| 376 | input Integer dim; | ||
| 377 | input GetArrayContents getArrayContents; | ||
| 378 | input ToString toString; | ||
| 379 | output list<Exp> outExps={}; | ||
| 380 | output list<Integer> outDims={}; | ||
| 381 | partial function GetArrayContents | ||
| 382 | input Exp e; | ||
| 383 | output list<Exp> es; | ||
| 384 | end GetArrayContents; | ||
| 385 | partial function ToString | ||
| 386 | input Exp e; | ||
| 387 | output String s; | ||
| 388 | end ToString; | ||
| 389 | protected | ||
| 390 | list<Exp> arr; | ||
| 391 | list<Integer> dims; | ||
| 392 | Integer i; | ||
| 393 | algorithm | ||
| 394 |
2/2✓ Branch 0 taken 20908 times.
✓ Branch 1 taken 20116 times.
|
41024 | if dim == 1 then |
| 395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20908 times.
|
20908 | outExps := getArrayContents(e); |
| 396 | 20908 | outDims := {listLength(outExps)}; | |
| 397 | 20908 | return; | |
| 398 | end if; | ||
| 399 | i := 0; | ||
| 400 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 20116 times.
✓ Branch 5 taken 20911 times.
✓ Branch 6 taken 20108 times.
|
41027 | for exp in listReverse(getArrayContents(e)) loop |
| 401 | 20911 | (arr, dims) := evalCatGetFlatArray(exp, dim-1, getArrayContents=getArrayContents, toString=toString); | |
| 402 |
2/2✓ Branch 0 taken 20108 times.
✓ Branch 1 taken 803 times.
|
20911 | if listEmpty(outDims) then |
| 403 | 20108 | outDims := dims; | |
| 404 | elseif not valueEq(dims, outDims) then | ||
| 405 | ✗ | Error.terminate(getInstanceName() + ": Got unbalanced array from " + toString(e), sourceInfo()); | |
| 406 | end if; | ||
| 407 | 20911 | outExps := listAppend(arr, outExps); | |
| 408 | 20911 | i := i+1; | |
| 409 | end for; | ||
| 410 | outDims := i :: outDims; | ||
| 411 | end evalCatGetFlatArray; | ||
| 412 | |||
| 413 | public function expEqual | ||
| 414 | "Returns true if the two expressions are equal, otherwise false." | ||
| 415 | input DAE.Exp inExp1; | ||
| 416 | input DAE.Exp inExp2; | ||
| 417 | output Boolean outEqual; | ||
| 418 | algorithm | ||
| 419 | 97526297 | outEqual := 0==compare(inExp1, inExp2); | |
| 420 | end expEqual; | ||
| 421 | |||
| 422 | function compare | ||
| 423 | input DAE.Exp inExp1, inExp2; | ||
| 424 | output Integer comp; | ||
| 425 | algorithm | ||
| 426 | // Return true if the references are the same. | ||
| 427 |
2/2✓ Branch 0 taken 9033154 times.
✓ Branch 1 taken 107777394 times.
|
116810548 | if referenceEq(inExp1, inExp2) then |
| 428 | comp := 0; | ||
| 429 | 9033154 | return; | |
| 430 | end if; | ||
| 431 | |||
| 432 | 107777394 | comp := Util.intCompare(valueConstructor(inExp1), valueConstructor(inExp2)); | |
| 433 | // Return false if the expressions are not of the same type. | ||
| 434 |
2/2✓ Branch 0 taken 62438024 times.
✓ Branch 1 taken 45339370 times.
|
107777394 | if comp <> 0 then |
| 435 | 62438024 | return; | |
| 436 | end if; | ||
| 437 | |||
| 438 | // Otherwise, check if the expressions are equal or not. | ||
| 439 | // Since the expressions have already been verified to be of the same type | ||
| 440 | // above we can match on only one of them to allow the pattern matching to | ||
| 441 | // optimize this to jump directly to the correct case. | ||
| 442 | comp := match inExp1 | ||
| 443 | local | ||
| 444 | Integer i; | ||
| 445 | Real r; | ||
| 446 | String s; | ||
| 447 | Boolean b; | ||
| 448 | Absyn.Path p; | ||
| 449 | DAE.Exp e, e1, e2; | ||
| 450 | Option<DAE.Exp> oe; | ||
| 451 | list<DAE.Exp> expl; | ||
| 452 | list<list<DAE.Exp>> mexpl; | ||
| 453 | DAE.Operator op; | ||
| 454 | DAE.ComponentRef cr; | ||
| 455 | DAE.Type ty; | ||
| 456 | list<DAE.Subscript> subs; | ||
| 457 | |||
| 458 | case DAE.ICONST() | ||
| 459 | algorithm | ||
| 460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 692987 times.
|
692987 | DAE.ICONST(integer = i) := inExp2; |
| 461 | 692987 | then | |
| 462 | Util.intCompare(inExp1.integer, i); | ||
| 463 | |||
| 464 | case DAE.RCONST() | ||
| 465 | algorithm | ||
| 466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3647982 times.
|
3647982 | DAE.RCONST(real = r) := inExp2; |
| 467 | 3647982 | then Util.realCompare(inExp1.real, r); | |
| 468 | |||
| 469 | case DAE.SCONST() | ||
| 470 | algorithm | ||
| 471 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 233273 times.
|
233273 | DAE.SCONST(string = s) := inExp2; |
| 472 | 233273 | then stringCompare(inExp1.string, s); | |
| 473 | |||
| 474 | case DAE.BCONST() | ||
| 475 | algorithm | ||
| 476 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2725 times.
|
2725 | DAE.BCONST(bool = b) := inExp2; |
| 477 | 2725 | then Util.boolCompare(inExp1.bool, b); | |
| 478 | |||
| 479 | case DAE.ENUM_LITERAL() | ||
| 480 | algorithm | ||
| 481 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38671 times.
|
38671 | DAE.ENUM_LITERAL(name = p) := inExp2; |
| 482 | 38671 | then AbsynUtil.pathCompare(inExp1.name, p); | |
| 483 | |||
| 484 | case DAE.CREF() | ||
| 485 | algorithm | ||
| 486 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16331243 times.
|
16331243 | DAE.CREF(componentRef = cr) := inExp2; |
| 487 | 16331243 | then ComponentReferenceBasics.crefCompareGeneric(inExp1.componentRef, cr); | |
| 488 | |||
| 489 | case DAE.ARRAY() | ||
| 490 | algorithm | ||
| 491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66084 times.
|
66084 | DAE.ARRAY(ty = ty, array = expl) := inExp2; |
| 492 | 66084 | comp := valueCompare(inExp1.ty, ty); | |
| 493 |
2/2✓ Branch 0 taken 65919 times.
✓ Branch 1 taken 165 times.
|
66084 | then if 0==comp then compareList(inExp1.array, expl) else comp; |
| 494 | |||
| 495 | case DAE.MATRIX() | ||
| 496 | algorithm | ||
| 497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1078 times.
|
1078 | DAE.MATRIX(ty = ty, matrix = mexpl) := inExp2; |
| 498 | 1078 | comp := valueCompare(inExp1.ty, ty); | |
| 499 |
1/2✓ Branch 0 taken 1078 times.
✗ Branch 1 not taken.
|
1078 | then if 0==comp then compareListList(inExp1.matrix, mexpl) else comp; |
| 500 | |||
| 501 | case DAE.BINARY() | ||
| 502 | algorithm | ||
| 503 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22432147 times.
|
22432147 | DAE.BINARY(exp1 = e1, operator = op, exp2 = e2) := inExp2; |
| 504 | 22432147 | comp := operatorCompare(inExp1.operator, op); | |
| 505 |
2/2✓ Branch 0 taken 12569886 times.
✓ Branch 1 taken 9862261 times.
|
22432147 | comp := if 0==comp then compare(inExp1.exp1, e1) else comp; |
| 506 |
2/2✓ Branch 0 taken 4092401 times.
✓ Branch 1 taken 18339746 times.
|
22432147 | then if 0==comp then compare(inExp1.exp2, e2) else comp; |
| 507 | |||
| 508 | case DAE.LBINARY() | ||
| 509 | algorithm | ||
| 510 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 134914 times.
|
134914 | DAE.LBINARY(exp1 = e1, operator = op, exp2 = e2) := inExp2; |
| 511 | 134914 | comp := operatorCompare(inExp1.operator, op); | |
| 512 |
2/2✓ Branch 0 taken 130556 times.
✓ Branch 1 taken 4358 times.
|
134914 | comp := if 0==comp then compare(inExp1.exp1, e1) else comp; |
| 513 |
2/2✓ Branch 0 taken 111277 times.
✓ Branch 1 taken 23637 times.
|
134914 | then if 0==comp then compare(inExp1.exp2, e2) else comp; |
| 514 | |||
| 515 | case DAE.UNARY() | ||
| 516 | algorithm | ||
| 517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 201997 times.
|
201997 | DAE.UNARY(exp = e, operator = op) := inExp2; |
| 518 | 201997 | comp := operatorCompare(inExp1.operator, op); | |
| 519 |
1/2✓ Branch 0 taken 201997 times.
✗ Branch 1 not taken.
|
201997 | then if 0==comp then compare(inExp1.exp, e) else comp; |
| 520 | |||
| 521 | case DAE.LUNARY() | ||
| 522 | algorithm | ||
| 523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2362 times.
|
2362 | DAE.LUNARY(exp = e, operator = op) := inExp2; |
| 524 | 2362 | comp := operatorCompare(inExp1.operator, op); | |
| 525 |
1/2✓ Branch 0 taken 2362 times.
✗ Branch 1 not taken.
|
2362 | then if 0==comp then compare(inExp1.exp, e) else comp; |
| 526 | |||
| 527 | case DAE.RELATION() | ||
| 528 | algorithm | ||
| 529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 293282 times.
|
293282 | DAE.RELATION(exp1 = e1, operator = op, exp2 = e2) := inExp2; |
| 530 | 293282 | comp := operatorCompare(inExp1.operator, op); | |
| 531 |
2/2✓ Branch 0 taken 208916 times.
✓ Branch 1 taken 84366 times.
|
293282 | comp := if 0==comp then compare(inExp1.exp1, e1) else comp; |
| 532 |
2/2✓ Branch 0 taken 161939 times.
✓ Branch 1 taken 131343 times.
|
293282 | then if 0==comp then compare(inExp1.exp2, e2) else comp; |
| 533 | |||
| 534 | case DAE.IFEXP() | ||
| 535 | algorithm | ||
| 536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25849 times.
|
25849 | DAE.IFEXP(expCond = e, expThen = e1, expElse = e2) := inExp2; |
| 537 | 25849 | comp := compare(inExp1.expCond, e); | |
| 538 |
2/2✓ Branch 0 taken 19186 times.
✓ Branch 1 taken 6663 times.
|
25849 | comp := if 0==comp then compare(inExp1.expThen, e1) else comp; |
| 539 |
2/2✓ Branch 0 taken 16615 times.
✓ Branch 1 taken 9234 times.
|
25849 | then if 0==comp then compare(inExp1.expElse, e2) else comp; |
| 540 | |||
| 541 | case DAE.CALL() | ||
| 542 | algorithm | ||
| 543 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1037081 times.
|
1037081 | DAE.CALL(path = p, expLst = expl) := inExp2; |
| 544 | 1037081 | comp := AbsynUtil.pathCompare(inExp1.path, p); | |
| 545 |
2/2✓ Branch 0 taken 953446 times.
✓ Branch 1 taken 83635 times.
|
1037081 | then if 0==comp then compareList(inExp1.expLst, expl) else comp; |
| 546 | |||
| 547 | case DAE.RECORD() | ||
| 548 | algorithm | ||
| 549 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14043 times.
|
14043 | DAE.RECORD(path = p, exps = expl) := inExp2; |
| 550 | 14043 | comp := AbsynUtil.pathCompare(inExp1.path, p); | |
| 551 |
1/2✓ Branch 0 taken 14043 times.
✗ Branch 1 not taken.
|
14043 | then if 0==comp then compareList(inExp1.exps, expl) else comp; |
| 552 | |||
| 553 | case DAE.PARTEVALFUNCTION() | ||
| 554 | algorithm | ||
| 555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 553 times.
|
553 | DAE.PARTEVALFUNCTION(path = p, expList = expl) := inExp2; |
| 556 | 553 | comp := AbsynUtil.pathCompare(inExp1.path, p); | |
| 557 |
1/2✓ Branch 0 taken 553 times.
✗ Branch 1 not taken.
|
553 | then if 0==comp then compareList(inExp1.expList, expl) else comp; |
| 558 | |||
| 559 | case DAE.RANGE() | ||
| 560 | algorithm | ||
| 561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | DAE.RANGE(start = e1, step = oe, stop = e2) := inExp2; |
| 562 | 4 | comp := compare(inExp1.start, e1); | |
| 563 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
|
4 | comp := if 0==comp then compare(inExp1.stop, e2) else comp; |
| 564 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
|
4 | then if 0==comp then compareOpt(inExp1.step, oe) else comp; |
| 565 | |||
| 566 | case DAE.TUPLE() | ||
| 567 | algorithm | ||
| 568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 528 times.
|
528 | DAE.TUPLE(PR = expl) := inExp2; |
| 569 | 528 | then compareList(inExp1.PR, expl); | |
| 570 | |||
| 571 | case DAE.CAST() | ||
| 572 | algorithm | ||
| 573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22358 times.
|
22358 | DAE.CAST(ty = ty, exp = e) := inExp2; |
| 574 | 22358 | comp := valueCompare(inExp1.ty, ty); | |
| 575 |
1/2✓ Branch 0 taken 22358 times.
✗ Branch 1 not taken.
|
22358 | then if 0==comp then compare(inExp1.exp, e) else comp; |
| 576 | |||
| 577 | case DAE.ASUB() | ||
| 578 | algorithm | ||
| 579 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11155 times.
|
11155 | DAE.ASUB(exp = e, sub = subs) := inExp2; |
| 580 | 11155 | comp := compare(inExp1.exp, e); | |
| 581 |
2/2✓ Branch 0 taken 7609 times.
✓ Branch 1 taken 3546 times.
|
11155 | then if comp==0 then compareSubscriptList(inExp1.sub, subs) else comp; |
| 582 | |||
| 583 | case DAE.RSUB() | ||
| 584 | algorithm | ||
| 585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126755 times.
|
126755 | DAE.RSUB(exp = e, ix=i, fieldName=s, ty=ty) := inExp2; |
| 586 | 126755 | comp := Util.intCompare(inExp1.ix, i); | |
| 587 |
2/2✓ Branch 0 taken 126741 times.
✓ Branch 1 taken 14 times.
|
126755 | comp := if comp==0 then valueCompare(inExp1.ty, ty) else comp; |
| 588 |
2/2✓ Branch 0 taken 126685 times.
✓ Branch 1 taken 70 times.
|
126755 | comp := if comp==0 then stringCompare(inExp1.fieldName, s) else comp; |
| 589 |
2/2✓ Branch 0 taken 37495 times.
✓ Branch 1 taken 89260 times.
|
126755 | then if comp==0 then compare(inExp1.exp, e) else comp; |
| 590 | |||
| 591 | case DAE.TSUB() | ||
| 592 | algorithm | ||
| 593 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | DAE.TSUB(exp = e, ix=i, ty = ty) := inExp2; |
| 594 | 70 | comp := Util.intCompare(inExp1.ix, i); | |
| 595 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | comp := if 0==comp then valueCompare(inExp1.ty, ty) else comp; |
| 596 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | then if 0==comp then compare(inExp1.exp, e) else comp; |
| 597 | |||
| 598 | case DAE.SIZE() | ||
| 599 | algorithm | ||
| 600 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | DAE.SIZE(exp = e, sz = oe) := inExp2; |
| 601 | 30 | comp := compare(inExp1.exp, e); | |
| 602 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | then if comp==0 then compareOpt(inExp1.sz, oe) else comp; |
| 603 | |||
| 604 | case DAE.REDUCTION() | ||
| 605 | // Reductions contain too much information to compare in a sane manner. | ||
| 606 | 4 | then valueCompare(inExp1, inExp2); | |
| 607 | |||
| 608 | case DAE.LIST() | ||
| 609 | algorithm | ||
| 610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | DAE.LIST(valList = expl) := inExp2; |
| 611 | 14 | then | |
| 612 | compareList(inExp1.valList, expl); | ||
| 613 | |||
| 614 | case DAE.CONS() | ||
| 615 | algorithm | ||
| 616 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 693 times.
|
693 | DAE.CONS(car = e1, cdr = e2) := inExp2; |
| 617 | 693 | comp := compare(inExp1.car, e1); | |
| 618 |
2/2✓ Branch 0 taken 691 times.
✓ Branch 1 taken 2 times.
|
693 | then if 0==comp then compare(inExp1.cdr, e2) else comp; |
| 619 | |||
| 620 | case DAE.META_TUPLE() | ||
| 621 | algorithm | ||
| 622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 604 times.
|
604 | DAE.META_TUPLE(listExp = expl) := inExp2; |
| 623 | 604 | then | |
| 624 | compareList(inExp1.listExp, expl); | ||
| 625 | |||
| 626 | case DAE.META_OPTION() | ||
| 627 | algorithm | ||
| 628 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
|
239 | DAE.META_OPTION(exp = oe) := inExp2; |
| 629 | 239 | then | |
| 630 | compareOpt(inExp1.exp, oe); | ||
| 631 | |||
| 632 | case DAE.METARECORDCALL() | ||
| 633 | algorithm | ||
| 634 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5298 times.
|
5298 | DAE.METARECORDCALL(path = p, args = expl) := inExp2; |
| 635 | 5298 | comp := AbsynUtil.pathCompare(inExp1.path, p); | |
| 636 |
2/2✓ Branch 0 taken 5155 times.
✓ Branch 1 taken 143 times.
|
5298 | then if comp==0 then compareList(inExp1.args, expl) else comp; |
| 637 | |||
| 638 | case DAE.MATCHEXPRESSION() | ||
| 639 | ✗ | then valueCompare(inExp1, inExp2); | |
| 640 | |||
| 641 | case DAE.BOX() | ||
| 642 | algorithm | ||
| 643 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3926 times.
|
3926 | DAE.BOX(exp = e) := inExp2; |
| 644 | 3926 | then | |
| 645 | compare(inExp1.exp, e); | ||
| 646 | |||
| 647 | case DAE.UNBOX() | ||
| 648 | algorithm | ||
| 649 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | DAE.UNBOX(exp = e) := inExp2; |
| 650 | 65 | then | |
| 651 | compare(inExp1.exp, e); | ||
| 652 | |||
| 653 | case DAE.SHARED_LITERAL() | ||
| 654 | algorithm | ||
| 655 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11169 times.
|
11169 | DAE.SHARED_LITERAL(index = i) := inExp2; |
| 656 | 11169 | then Util.intCompare(inExp1.index, i); | |
| 657 | |||
| 658 | case DAE.EMPTY() | ||
| 659 | algorithm | ||
| 660 | ✗ | DAE.EMPTY(name=cr) := inExp2; | |
| 661 | ✗ | then ComponentReferenceBasics.crefCompareGeneric(inExp1.name, cr); | |
| 662 | |||
| 663 | case DAE.CODE() | ||
| 664 | 187 | then valueCompare(inExp1, inExp2); | |
| 665 | |||
| 666 | else | ||
| 667 | algorithm | ||
| 668 | ✗ | Error.addInternalError("ExpressionBasics.compare failed: ctor:" + String(valueConstructor(inExp1)) + " " + printExpStr(inExp1) + " " + printExpStr(inExp2), sourceInfo()); | |
| 669 | ✗ | then fail(); | |
| 670 | end match; | ||
| 671 | end compare; | ||
| 672 | |||
| 673 | protected function compareList | ||
| 674 | input list<DAE.Exp> inExpl1; | ||
| 675 | input list<DAE.Exp> inExpl2; | ||
| 676 | output Integer comp; | ||
| 677 | protected | ||
| 678 | Integer len1, len2; | ||
| 679 | DAE.Exp e2; | ||
| 680 | list<DAE.Exp> rest_expl2 = inExpl2; | ||
| 681 | algorithm | ||
| 682 | // Check that the lists have the same length, otherwise they can't be equal. | ||
| 683 | 1042436 | len1 := listLength(inExpl1); | |
| 684 | 1042436 | len2 := listLength(inExpl2); | |
| 685 | 1042436 | comp := Util.intCompare(len1, len2); | |
| 686 |
2/2✓ Branch 0 taken 1036893 times.
✓ Branch 1 taken 5543 times.
|
1042436 | if comp <> 0 then |
| 687 | 5543 | return; | |
| 688 | end if; | ||
| 689 | |||
| 690 |
2/2✓ Branch 0 taken 1546383 times.
✓ Branch 1 taken 394548 times.
|
1940931 | for e1 in inExpl1 loop |
| 691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1546383 times.
|
1546383 | e2 :: rest_expl2 := rest_expl2; |
| 692 | |||
| 693 | // Return false if the expressions are not equal. | ||
| 694 | 1546383 | comp := compare(e1, e2); | |
| 695 |
2/2✓ Branch 0 taken 642345 times.
✓ Branch 1 taken 904038 times.
|
1546383 | if 0 <> comp then |
| 696 | 642345 | return; | |
| 697 | end if; | ||
| 698 | end for; | ||
| 699 | |||
| 700 | comp := 0; | ||
| 701 | end compareList; | ||
| 702 | |||
| 703 | protected function compareListList | ||
| 704 | input list<list<DAE.Exp>> inExpl1; | ||
| 705 | input list<list<DAE.Exp>> inExpl2; | ||
| 706 | output Integer comp; | ||
| 707 | protected | ||
| 708 | list<DAE.Exp> expl2; | ||
| 709 | list<list<DAE.Exp>> rest_expl2 = inExpl2; | ||
| 710 | Integer len1, len2; | ||
| 711 | algorithm | ||
| 712 | // Check that the lists have the same length, otherwise they can't be equal. | ||
| 713 | 1078 | len1 := listLength(inExpl1); | |
| 714 | 1078 | len2 := listLength(inExpl2); | |
| 715 | 1078 | comp := Util.intCompare(len1, len2); | |
| 716 |
1/2✓ Branch 0 taken 1078 times.
✗ Branch 1 not taken.
|
1078 | if comp <> 0 then |
| 717 | ✗ | return; | |
| 718 | end if; | ||
| 719 | |||
| 720 |
2/2✓ Branch 0 taken 2174 times.
✓ Branch 1 taken 505 times.
|
2679 | for expl1 in inExpl1 loop |
| 721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2174 times.
|
2174 | expl2 :: rest_expl2 := rest_expl2; |
| 722 | |||
| 723 | // Return false if the expression lists are not equal. | ||
| 724 | 2174 | comp := compareList(expl1, expl2); | |
| 725 |
2/2✓ Branch 0 taken 573 times.
✓ Branch 1 taken 1601 times.
|
2174 | if 0 <> comp then |
| 726 | 573 | return; | |
| 727 | end if; | ||
| 728 | end for; | ||
| 729 | |||
| 730 | comp := 0; | ||
| 731 | end compareListList; | ||
| 732 | |||
| 733 | protected function compareOpt | ||
| 734 | input Option<DAE.Exp> inExp1; | ||
| 735 | input Option<DAE.Exp> inExp2; | ||
| 736 | output Integer comp; | ||
| 737 | protected | ||
| 738 | DAE.Exp e1, e2; | ||
| 739 | algorithm | ||
| 740 | comp := match(inExp1, inExp2) | ||
| 741 | case (NONE(), NONE()) then 0; | ||
| 742 | case (NONE(), _) then -1; | ||
| 743 | case (_, NONE()) then 1; | ||
| 744 | 269 | case (SOME(e1), SOME(e2)) then compare(e1, e2); | |
| 745 | end match; | ||
| 746 | end compareOpt; | ||
| 747 | |||
| 748 | public function operatorCompare | ||
| 749 | "Helper function to expEqual." | ||
| 750 | input DAE.Operator inOperator1; | ||
| 751 | input DAE.Operator inOperator2; | ||
| 752 | output Integer comp; | ||
| 753 | algorithm | ||
| 754 | comp := match (inOperator1,inOperator2) | ||
| 755 | local | ||
| 756 | Absyn.Path p1,p2; | ||
| 757 | |||
| 758 | case (DAE.USERDEFINED(fqName = p1),DAE.USERDEFINED(fqName = p2)) | ||
| 759 | ✗ | then AbsynUtil.pathCompare(p1, p2); | |
| 760 | 29684975 | else Util.intCompare(valueConstructor(inOperator1), valueConstructor(inOperator2)); | |
| 761 | end match; | ||
| 762 | end operatorCompare; | ||
| 763 | |||
| 764 | function compareSubscripts | ||
| 765 | input DAE.Subscript sub1; | ||
| 766 | input DAE.Subscript sub2; | ||
| 767 | output Integer res; | ||
| 768 | algorithm | ||
| 769 |
2/2✓ Branch 0 taken 35881 times.
✓ Branch 1 taken 20339 times.
|
56220 | if referenceEq(sub1, sub2) then |
| 770 | res := 0; | ||
| 771 | else | ||
| 772 | res := match (sub1, sub2) | ||
| 773 | case (DAE.Subscript.WHOLEDIM(), DAE.Subscript.WHOLEDIM()) then 0; | ||
| 774 | ✗ | case (DAE.Subscript.SLICE(), DAE.Subscript.SLICE()) then compare(sub1.exp, sub2.exp); | |
| 775 | 35881 | case (DAE.Subscript.INDEX(), DAE.Subscript.INDEX()) then compare(sub1.exp, sub2.exp); | |
| 776 | ✗ | case (DAE.Subscript.WHOLE_NONEXP(), DAE.Subscript.WHOLE_NONEXP()) then compare(sub1.exp, sub2.exp); | |
| 777 | ✗ | else Util.intCompare(valueConstructor(sub1), valueConstructor(sub2)); | |
| 778 | end match; | ||
| 779 | end if; | ||
| 780 | end compareSubscripts; | ||
| 781 | |||
| 782 | protected function compareSubscriptList | ||
| 783 | input list<DAE.Subscript> subs1; | ||
| 784 | input list<DAE.Subscript> subs2; | ||
| 785 | output Integer comp; | ||
| 786 | protected | ||
| 787 | Integer len1, len2; | ||
| 788 | DAE.Subscript s2; | ||
| 789 | list<DAE.Subscript> rest_subs2 = subs2; | ||
| 790 | algorithm | ||
| 791 | // Check that the lists have the same length, otherwise they can't be equal. | ||
| 792 | 7609 | len1 := listLength(subs1); | |
| 793 | 7609 | len2 := listLength(subs2); | |
| 794 | 7609 | comp := Util.intCompare(len1, len2); | |
| 795 |
1/2✓ Branch 0 taken 7609 times.
✗ Branch 1 not taken.
|
7609 | if comp <> 0 then |
| 796 | ✗ | return; | |
| 797 | end if; | ||
| 798 | |||
| 799 |
2/2✓ Branch 0 taken 8203 times.
✓ Branch 1 taken 1096 times.
|
9299 | for s1 in subs1 loop |
| 800 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8203 times.
|
8203 | s2 :: rest_subs2 := rest_subs2; |
| 801 | |||
| 802 | // Return false if the expressions are not equal. | ||
| 803 | 8203 | comp := compareSubscripts(s1, s2); | |
| 804 |
2/2✓ Branch 0 taken 6513 times.
✓ Branch 1 taken 1690 times.
|
8203 | if 0 <> comp then |
| 805 | 6513 | return; | |
| 806 | end if; | ||
| 807 | end for; | ||
| 808 | |||
| 809 | comp := 0; | ||
| 810 | end compareSubscriptList; | ||
| 811 | |||
| 812 | |||
| 813 | public function subscriptInt | ||
| 814 | "Tries to convert a subscript to an integer index." | ||
| 815 | input DAE.Subscript inSubscript; | ||
| 816 | output Integer outInteger = expArrayIndex(subscriptIndexExp(inSubscript)); | ||
| 817 | end subscriptInt; | ||
| 818 | |||
| 819 | public function subscriptsInt | ||
| 820 | "Tries to convert a list of subscripts to integer indices." | ||
| 821 | input list<DAE.Subscript> inSubscripts; | ||
| 822 | output list<Integer> outIntegers; | ||
| 823 | algorithm | ||
| 824 | 618056 | outIntegers := List.map(inSubscripts, subscriptInt); | |
| 825 | end subscriptsInt; | ||
| 826 | |||
| 827 | public function expArrayIndex | ||
| 828 | "Returns the array index that an expression represents as an integer." | ||
| 829 | input DAE.Exp inExp; | ||
| 830 | output Integer outIndex; | ||
| 831 | algorithm | ||
| 832 | outIndex := match inExp | ||
| 833 | 1201894 | case DAE.ICONST() then inExp.integer; | |
| 834 | 27594 | case DAE.ENUM_LITERAL() then inExp.index; | |
| 835 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | case DAE.BCONST() then if inExp.bool then 2 else 1; |
| 836 | end match; | ||
| 837 | end expArrayIndex; | ||
| 838 | |||
| 839 | public function subscriptIndexExp | ||
| 840 | "Returns the expression in a subscript index. | ||
| 841 | If the subscript is not an index the function fails." | ||
| 842 | input DAE.Subscript inSubscript; | ||
| 843 | output DAE.Exp outExp; | ||
| 844 | algorithm | ||
| 845 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1017724 times.
|
1017724 | DAE.INDEX(exp = outExp) := inSubscript; |
| 846 | end subscriptIndexExp; | ||
| 847 | |||
| 848 | public function subscriptEqual | ||
| 849 | "Returns true if two subscript lists are equal." | ||
| 850 | input list<DAE.Subscript> inSubscriptLst1; | ||
| 851 | input list<DAE.Subscript> inSubscriptLst2; | ||
| 852 | output Boolean outBoolean; | ||
| 853 | algorithm | ||
| 854 | outBoolean := match (inSubscriptLst1,inSubscriptLst2) | ||
| 855 | local | ||
| 856 | list<DAE.Subscript> xs1,xs2; | ||
| 857 | DAE.Exp e1,e2; | ||
| 858 | Integer i1,i2; | ||
| 859 | |||
| 860 | // both lists are empty | ||
| 861 | case ({},{}) then true; | ||
| 862 | |||
| 863 | // wholedims as list heads, compare the rest | ||
| 864 | case ((DAE.WHOLEDIM() :: xs1),(DAE.WHOLEDIM() :: xs2)) | ||
| 865 | 2 | then subscriptEqual(xs1, xs2); | |
| 866 | |||
| 867 | // slices as heads, compare the slice exps and then compare the rest | ||
| 868 | case ((DAE.SLICE(exp = e1) :: xs1),(DAE.SLICE(exp = e2) :: xs2)) | ||
| 869 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | then if expEqual(e1, e2) then subscriptEqual(xs1, xs2) else false; |
| 870 | |||
| 871 | case ((DAE.INDEX(exp = DAE.ICONST(i1)) :: xs1),(DAE.INDEX(exp = DAE.ICONST(i2)) :: xs2)) | ||
| 872 |
2/2✓ Branch 0 taken 14582045 times.
✓ Branch 1 taken 3158217 times.
|
17740262 | then if i1 == i2 then subscriptEqual(xs1, xs2) else false; |
| 873 | |||
| 874 | // indexes as heads, compare the index exps and then compare the rest | ||
| 875 | case ((DAE.INDEX(exp = e1) :: xs1),(DAE.INDEX(exp = e2) :: xs2)) | ||
| 876 |
2/2✓ Branch 1 taken 4123 times.
✓ Branch 2 taken 3769 times.
|
7892 | then if expEqual(e1, e2) then subscriptEqual(xs1, xs2) else false; |
| 877 | |||
| 878 | case ((DAE.WHOLE_NONEXP(exp = e1) :: xs1),(DAE.WHOLE_NONEXP(exp = e2) :: xs2)) | ||
| 879 | ✗ | then if expEqual(e1, e2) then subscriptEqual(xs1, xs2) else false; | |
| 880 | |||
| 881 | // subscripts are not equal, return false | ||
| 882 | else false; | ||
| 883 | end match; | ||
| 884 | end subscriptEqual; | ||
| 885 | |||
| 886 | public function printListStr | ||
| 887 | "Same as printList, except it returns | ||
| 888 | a string instead of printing." | ||
| 889 | input list<Type_a> inTypeALst; | ||
| 890 | input FuncTypeType_aToString inFuncTypeTypeAToString; | ||
| 891 | input String inString; | ||
| 892 | output String outString; | ||
| 893 | replaceable type Type_a subtypeof Any; | ||
| 894 | partial function FuncTypeType_aToString | ||
| 895 | input Type_a inTypeA; | ||
| 896 | output String outString; | ||
| 897 | end FuncTypeType_aToString; | ||
| 898 | algorithm | ||
| 899 | 482450 | outString := stringDelimitList(List.map(inTypeALst,inFuncTypeTypeAToString),inString); | |
| 900 | end printListStr; | ||
| 901 | |||
| 902 | public function printSubscriptStr " | ||
| 903 | Print a Subscript into a String." | ||
| 904 | input DAE.Subscript sub; | ||
| 905 | output String outString; | ||
| 906 | algorithm | ||
| 907 | outString := match sub | ||
| 908 | case DAE.WHOLEDIM() then ":"; | ||
| 909 | 646902 | case DAE.INDEX() then printExpStr(sub.exp); | |
| 910 | 12 | case DAE.SLICE() then printExpStr(sub.exp); | |
| 911 | ✗ | case DAE.WHOLE_NONEXP() then "1:" + printExpStr(sub.exp); | |
| 912 | end match; | ||
| 913 | end printSubscriptStr; | ||
| 914 | |||
| 915 | public function hashExp "help function to hashExpMod" | ||
| 916 | input DAE.Exp e; | ||
| 917 | output Integer hash; | ||
| 918 | algorithm | ||
| 919 | hash := matchcontinue e | ||
| 920 | local | ||
| 921 | Real r; | ||
| 922 | Integer i; | ||
| 923 | Boolean b; | ||
| 924 | String s; | ||
| 925 | Absyn.Path path; | ||
| 926 | DAE.Exp e1,e2,e3; | ||
| 927 | DAE.Operator op; | ||
| 928 | list<DAE.Exp> expl; | ||
| 929 | list<list<DAE.Exp>> mexpl; | ||
| 930 | DAE.ComponentRef cr; | ||
| 931 | DAE.ReductionIterators iters; | ||
| 932 | DAE.ReductionInfo info; | ||
| 933 | list<DAE.Subscript> subs; | ||
| 934 | |||
| 935 | 109388 | case DAE.ICONST(i) then stringHashDjb2(intString(i)); | |
| 936 | 1315825 | case DAE.RCONST(r) then stringHashDjb2(realString(r)); | |
| 937 |
2/2✓ Branch 0 taken 25466 times.
✓ Branch 1 taken 14401 times.
|
65333 | case DAE.BCONST(b) then stringHashDjb2(boolString(b)); |
| 938 | 466231 | case DAE.SCONST(s) then stringHashDjb2(s); | |
| 939 | 221579 | case DAE.ENUM_LITERAL(name=path) then stringHashDjb2(AbsynUtil.pathString(path)); | |
| 940 | 2489884 | case DAE.CREF(componentRef=cr) then ComponentReferenceBasics.hashComponentRef(cr); | |
| 941 | |||
| 942 | 1381697 | case DAE.BINARY(e1,op,e2) then 1 + hashExp(e1)+hashOp(op)+hashExp(e2); | |
| 943 | 52857 | case DAE.UNARY(op,e1) then 2 + hashOp(op)+hashExp(e1); | |
| 944 | 153313 | case DAE.LBINARY(e1,op,e2) then 3 + hashExp(e1)+hashOp(op)+hashExp(e2); | |
| 945 | 15692 | case DAE.LUNARY(op,e1) then 4 + hashOp(op)+hashExp(e1); | |
| 946 | 374494 | case DAE.RELATION(e1,op,e2,_,_) then 5 + hashExp(e1)+hashOp(op)+hashExp(e2); | |
| 947 | 27294 | case DAE.IFEXP(e1,e2,e3) then 6 + hashExp(e1)+hashExp(e2)+hashExp(e3); | |
| 948 | 435923 | case DAE.CALL(path=path,expLst=expl) then 7 + stringHashDjb2(AbsynUtil.pathString(path))+List.reduce(List.map(expl,hashExp),intAdd); | |
| 949 | 15641 | case DAE.RECORD(path=path,exps=expl) then 8 + stringHashDjb2(AbsynUtil.pathString(path))+List.reduce(List.map(expl,hashExp),intAdd); | |
| 950 | 1002 | case DAE.PARTEVALFUNCTION(path=path,expList=expl) then 9 + stringHashDjb2(AbsynUtil.pathString(path))+List.reduce(List.map(expl,hashExp),intAdd); | |
| 951 | 83417 | case DAE.ARRAY(array=expl) then 10 + List.reduce(List.map(expl,hashExp),intAdd); | |
| 952 | 1224 | case DAE.MATRIX(matrix=mexpl) then 11 + List.reduce(List.map(List.flatten(mexpl),hashExp),intAdd); | |
| 953 | 6 | case DAE.RANGE(_,e1,SOME(e2),e3) then 12 + hashExp(e1)+hashExp(e2)+hashExp(e3); | |
| 954 | 9973 | case DAE.RANGE(_,e1,NONE(),e3) then 13 + hashExp(e1)+hashExp(e3); | |
| 955 | 36 | case DAE.TUPLE(expl) then 14 + List.reduce(List.map(expl,hashExp),intAdd); | |
| 956 | 4336 | case DAE.CAST(_,e1) then 15 + hashExp(e1); | |
| 957 |
4/4✓ Branch 0 taken 2833 times.
✓ Branch 1 taken 2231 times.
✓ Branch 2 taken 2833 times.
✓ Branch 3 taken 2231 times.
|
5064 | case DAE.ASUB(e1,subs) then 16 + hashExp(e1)+List.reduce(list(hashExp(getSubscriptExp(sub)) for sub in subs),intAdd); |
| 958 | 68 | case DAE.TSUB(e1,i,_) then 17 + hashExp(e1)+stringHashDjb2(intString(i)); | |
| 959 | 9 | case DAE.SIZE(e1,SOME(e2)) then 18 + hashExp(e1)+hashExp(e2); | |
| 960 | ✗ | case DAE.SIZE(e1,NONE()) then 19 + hashExp(e1); | |
| 961 | // case(DAE.CODE(_,_)) then 20; // TODO: implement hashing of CODE AST | ||
| 962 | // case(DAE.EMPTY(scope=_)) then 21; // TODO: implement hashing of EMTPY (needed ?) | ||
| 963 | ✗ | case DAE.REDUCTION(info,e1,iters) then 22 + hashReductionInfo(info)+hashExp(e1)+List.reduce(List.map(iters,hashReductionIter),intAdd); | |
| 964 | // TODO: hashing of all MetaModelica extensions | ||
| 965 | 37912 | else stringHashDjb2(printExpStr(e)); | |
| 966 | end matchcontinue; | ||
| 967 | end hashExp; | ||
| 968 | |||
| 969 | protected function hashReductionInfo "help function to hashExp" | ||
| 970 | input DAE.ReductionInfo info; | ||
| 971 | output Integer hash; | ||
| 972 | algorithm | ||
| 973 | hash := match info | ||
| 974 | local | ||
| 975 | Absyn.Path path; | ||
| 976 | |||
| 977 | // TODO: complete hasing of all subexpressions | ||
| 978 | ✗ | case DAE.REDUCTIONINFO(path=path) then 22 + stringHashDjb2(AbsynUtil.pathString(path)); | |
| 979 | end match; | ||
| 980 | end hashReductionInfo; | ||
| 981 | |||
| 982 | protected function hashReductionIter "help function to hashExp" | ||
| 983 | input DAE.ReductionIterator iter; | ||
| 984 | output Integer hash; | ||
| 985 | algorithm | ||
| 986 | hash := match iter | ||
| 987 | local | ||
| 988 | String id; | ||
| 989 | DAE.Exp e1,e2; | ||
| 990 | |||
| 991 | |||
| 992 | ✗ | case DAE.REDUCTIONITER(id,e1,SOME(e2),_) then 23 + stringHashDjb2(id)+hashExp(e1)+hashExp(e2); | |
| 993 | ✗ | case DAE.REDUCTIONITER(id,e1,NONE(),_) then 24 + stringHashDjb2(id)+hashExp(e1); | |
| 994 | end match; | ||
| 995 | |||
| 996 | end hashReductionIter; | ||
| 997 | |||
| 998 | protected function hashOp "help function to hashExp" | ||
| 999 | input DAE.Operator op; | ||
| 1000 | output Integer hash; | ||
| 1001 | algorithm | ||
| 1002 | hash := match op | ||
| 1003 | local | ||
| 1004 | Absyn.Path path; | ||
| 1005 | |||
| 1006 | case DAE.ADD(_) then 25; | ||
| 1007 | case DAE.SUB(_) then 26; | ||
| 1008 | case DAE.MUL(_) then 27; | ||
| 1009 | case DAE.DIV(_) then 28; | ||
| 1010 | case DAE.POW(_) then 29; | ||
| 1011 | case DAE.UMINUS(_) then 30; | ||
| 1012 | case DAE.UMINUS_ARR(_) then 31; | ||
| 1013 | case DAE.ADD_ARR(_) then 32; | ||
| 1014 | case DAE.SUB_ARR(_) then 33; | ||
| 1015 | case DAE.MUL_ARR(_) then 34; | ||
| 1016 | case DAE.DIV_ARR(_) then 35; | ||
| 1017 | case DAE.MUL_ARRAY_SCALAR(_) then 36; | ||
| 1018 | case DAE.ADD_ARRAY_SCALAR(_) then 37; | ||
| 1019 | case DAE.SUB_SCALAR_ARRAY(_) then 38; | ||
| 1020 | case DAE.MUL_SCALAR_PRODUCT(_) then 39; | ||
| 1021 | case DAE.MUL_MATRIX_PRODUCT(_) then 40; | ||
| 1022 | case DAE.DIV_ARRAY_SCALAR(_) then 41; | ||
| 1023 | case DAE.DIV_SCALAR_ARRAY(_) then 42; | ||
| 1024 | case DAE.POW_ARRAY_SCALAR(_) then 43; | ||
| 1025 | case DAE.POW_SCALAR_ARRAY(_) then 44; | ||
| 1026 | case DAE.POW_ARR(_) then 45; | ||
| 1027 | case DAE.POW_ARR2(_) then 46; | ||
| 1028 | case DAE.AND(_) then 47; | ||
| 1029 | case DAE.OR(_) then 48; | ||
| 1030 | case DAE.NOT(_) then 49; | ||
| 1031 | case DAE.LESS(_) then 50; | ||
| 1032 | case DAE.LESSEQ(_) then 51; | ||
| 1033 | case DAE.GREATER(_) then 52; | ||
| 1034 | case DAE.GREATEREQ(_) then 53; | ||
| 1035 | case DAE.EQUAL(_) then 54; | ||
| 1036 | case DAE.NEQUAL(_) then 55; | ||
| 1037 | ✗ | case DAE.USERDEFINED(path) then 56 + stringHashDjb2(AbsynUtil.pathString(path)) ; | |
| 1038 | end match; | ||
| 1039 | end hashOp; | ||
| 1040 | |||
| 1041 | protected function getSubscriptExp | ||
| 1042 | "Returns the subscript expression, or fails on DAE.WHOLEDIM." | ||
| 1043 | input DAE.Subscript inSubscript; | ||
| 1044 | output DAE.Exp outExp; | ||
| 1045 | algorithm | ||
| 1046 | outExp := match inSubscript | ||
| 1047 | local DAE.Exp e; | ||
| 1048 | |||
| 1049 | case DAE.SLICE(exp = e) then e; | ||
| 1050 | case DAE.INDEX(exp = e) then e; | ||
| 1051 | case DAE.WHOLE_NONEXP(exp = e) then e; | ||
| 1052 | end match; | ||
| 1053 | end getSubscriptExp; | ||
| 1054 | |||
| 1055 | annotation(__OpenModelica_Interface="frontend_dump"); | ||
| 1056 | end ExpressionBasics; | ||
| 1057 |