OMCompiler/Compiler/NFFrontEnd/NFInstUtil.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 NFInstUtil | ||
| 37 | import Absyn; | ||
| 38 | import Algorithm = NFAlgorithm; | ||
| 39 | import Binding = NFBinding; | ||
| 40 | import Call = NFCall; | ||
| 41 | import Class = NFClass; | ||
| 42 | import NFClassTree.ClassTree; | ||
| 43 | import Component = NFComponent; | ||
| 44 | import ComponentRef = NFComponentRef; | ||
| 45 | import Equation = NFEquation; | ||
| 46 | import Expression = NFExpression; | ||
| 47 | import FlatModel = NFFlatModel; | ||
| 48 | import NFFlatten.FunctionTree; | ||
| 49 | import NFFunction.Function; | ||
| 50 | import NFInstNode.InstNode; | ||
| 51 | import NFPrefixes.{Variability, Purity}; | ||
| 52 | import SCode; | ||
| 53 | import Statement = NFStatement; | ||
| 54 | import Subscript = NFSubscript; | ||
| 55 | import Type = NFType; | ||
| 56 | import Variable = NFVariable; | ||
| 57 | |||
| 58 | protected | ||
| 59 | import AbsynUtil; | ||
| 60 | import DAE; | ||
| 61 | import BaseModelica; | ||
| 62 | import SCodeUtil; | ||
| 63 | import Dump; | ||
| 64 | import ElementSource; | ||
| 65 | import Flags; | ||
| 66 | import UnorderedMap; | ||
| 67 | import MetaModelica.Dangerous.listReverseInPlace; | ||
| 68 | import SCodeDump; | ||
| 69 | import ExecStat.execStat; | ||
| 70 | |||
| 71 | public | ||
| 72 | function dumpFlatModelDebug | ||
| 73 | input String stage; | ||
| 74 | input FlatModel flatModel; | ||
| 75 | input FunctionTree functions = FunctionTree.new(); | ||
| 76 | protected | ||
| 77 | FlatModel flat_model = flatModel; | ||
| 78 | algorithm | ||
| 79 |
4/8✓ Branch 1 taken 6 times.
✓ Branch 2 taken 8909 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 8909 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
8915 | if Flags.getConfigString(Flags.OBFUSCATE) == "protected" or |
| 80 | Flags.getConfigString(Flags.OBFUSCATE) == "encrypted" then | ||
| 81 | 6 | flat_model := FlatModel.obfuscate(flat_model); | |
| 82 | end if; | ||
| 83 | |||
| 84 | // --dumpFlatModel=stage dumps specific stages, --dumpFlatModel dumps all stages. | ||
| 85 |
3/4✓ Branch 1 taken 8915 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8909 times.
✓ Branch 5 taken 6 times.
|
8915 | if Flags.isConfigFlagSet(Flags.DUMP_FLAT_MODEL, stage) or |
| 86 | listEmpty(Flags.getConfigStringList(Flags.DUMP_FLAT_MODEL)) then | ||
| 87 | 6 | flat_model := combineSubscripts(flatModel); | |
| 88 | |||
| 89 | 6 | print("########################################\n"); | |
| 90 | 6 | print(stage); | |
| 91 | 6 | print("\n########################################\n\n"); | |
| 92 | |||
| 93 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if Flags.getConfigBool(Flags.BASE_MODELICA) then |
| 94 | ✗ | FlatModel.printFlatString(flat_model, functions); | |
| 95 | else | ||
| 96 | 6 | FlatModel.printString(flat_model, functions); | |
| 97 | end if; | ||
| 98 | |||
| 99 | 6 | print("\n"); | |
| 100 | end if; | ||
| 101 | end dumpFlatModelDebug; | ||
| 102 | |||
| 103 | function combineSubscripts | ||
| 104 | input output FlatModel flatModel; | ||
| 105 | algorithm | ||
| 106 |
2/2✓ Branch 1 taken 1465 times.
✓ Branch 2 taken 3 times.
|
1468 | if Flags.isSet(Flags.COMBINE_SUBSCRIPTS) then |
| 107 | 3 | flatModel := FlatModel.mapExp(flatModel, combineSubscriptsExp); | |
| 108 | end if; | ||
| 109 | end combineSubscripts; | ||
| 110 | |||
| 111 | function combineSubscriptsExp | ||
| 112 | input output Expression exp; | ||
| 113 | protected | ||
| 114 | function traverser | ||
| 115 | input output Expression exp; | ||
| 116 | algorithm | ||
| 117 | () := match exp | ||
| 118 | case Expression.CREF() | ||
| 119 | algorithm | ||
| 120 | 58 | exp.cref := ComponentRef.combineSubscripts(exp.cref); | |
| 121 | then | ||
| 122 | (); | ||
| 123 | |||
| 124 | else (); | ||
| 125 | end match; | ||
| 126 | end traverser; | ||
| 127 | algorithm | ||
| 128 | 55 | exp := Expression.map(exp, traverser); | |
| 129 | end combineSubscriptsExp; | ||
| 130 | |||
| 131 | function printStructuralParameters | ||
| 132 | input FlatModel flatModel; | ||
| 133 | protected | ||
| 134 | list<Variable> params; | ||
| 135 | list<String> names; | ||
| 136 | algorithm | ||
| 137 |
1/2✓ Branch 1 taken 1435 times.
✗ Branch 2 not taken.
|
1435 | if Flags.isSet(Flags.PRINT_STRUCTURAL) then |
| 138 | ✗ | params := list(v for v guard Variable.isStructural(v) in flatModel.variables); | |
| 139 | |||
| 140 | ✗ | if not listEmpty(params) then | |
| 141 | ✗ | names := list(ComponentRef.toString(v.name) for v in params); | |
| 142 | ✗ | Error.addMessage(Error.NOTIFY_FRONTEND_STRUCTURAL_PARAMETERS, | |
| 143 | {stringDelimitList(names, ", ")}); | ||
| 144 | end if; | ||
| 145 | end if; | ||
| 146 | end printStructuralParameters; | ||
| 147 | |||
| 148 | function dumpFlatModel | ||
| 149 | input FlatModel flatModel; | ||
| 150 | input FunctionTree functions; | ||
| 151 | output String str; | ||
| 152 | protected | ||
| 153 | FlatModel flat_model; | ||
| 154 | algorithm | ||
| 155 | 32 | flat_model := combineSubscripts(flatModel); | |
| 156 | 32 | str := FlatModel.toFlatString(flat_model, functions); | |
| 157 | end dumpFlatModel; | ||
| 158 | |||
| 159 | function replaceEmptyArrays | ||
| 160 | input output FlatModel flatModel; | ||
| 161 | algorithm | ||
| 162 | 1435 | flatModel := FlatModel.mapExp(flatModel, replaceEmptyArraysExp); | |
| 163 | end replaceEmptyArrays; | ||
| 164 | |||
| 165 | function replaceEmptyArraysExp | ||
| 166 | "Variables with 0-dimensions are not present in the flat model, so replace | ||
| 167 | any cref that refers to such a variable with an empty array expression." | ||
| 168 | input output Expression exp; | ||
| 169 | protected | ||
| 170 | function traverser | ||
| 171 | input Expression exp; | ||
| 172 | output Expression outExp; | ||
| 173 | protected | ||
| 174 | ComponentRef cref; | ||
| 175 | list<Subscript> subs; | ||
| 176 | Type ty; | ||
| 177 | algorithm | ||
| 178 | outExp := match exp | ||
| 179 | case Expression.CREF(cref = cref) | ||
| 180 | guard ComponentRef.isEmptyArray(cref) | ||
| 181 | algorithm | ||
| 182 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | if ComponentRef.hasSubscripts(cref) then |
| 183 | 20 | cref := ComponentRef.fillSubscripts(cref); | |
| 184 | 20 | cref := ComponentRef.replaceWholeSubscripts(cref); | |
| 185 | 20 | subs := ComponentRef.subscriptsAllFlat(cref); | |
| 186 | 20 | cref := ComponentRef.stripSubscriptsAll(cref); | |
| 187 | 20 | ty := ComponentRef.getSubscriptedType(cref); | |
| 188 | else | ||
| 189 | subs := {}; | ||
| 190 | ✗ | ty := exp.ty; | |
| 191 | end if; | ||
| 192 | |||
| 193 | 20 | outExp := Expression.makeEmptyArray(ty); | |
| 194 | |||
| 195 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if not listEmpty(subs) then |
| 196 | 20 | outExp := Expression.SUBSCRIPTED_EXP(outExp, subs, exp.ty, false); | |
| 197 | end if; | ||
| 198 | then | ||
| 199 | outExp; | ||
| 200 | |||
| 201 | else exp; | ||
| 202 | end match; | ||
| 203 | end traverser; | ||
| 204 | algorithm | ||
| 205 | 1106818 | exp := Expression.map(exp, traverser); | |
| 206 | end replaceEmptyArraysExp; | ||
| 207 | |||
| 208 | function expandSlicedCrefs | ||
| 209 | input output FlatModel flatModel; | ||
| 210 | input output FunctionTree functions; | ||
| 211 | algorithm | ||
| 212 |
4/4✓ Branch 1 taken 1428 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 217 times.
✓ Branch 5 taken 1211 times.
|
1430 | if Flags.isSet(Flags.COMBINE_SUBSCRIPTS) or not Flags.isSet(Flags.NF_SCALARIZE) then |
| 213 | 219 | return; | |
| 214 | end if; | ||
| 215 | |||
| 216 |
4/4✓ Branch 0 taken 371655 times.
✓ Branch 1 taken 1211 times.
✓ Branch 2 taken 371655 times.
✓ Branch 3 taken 1211 times.
|
374077 | flatModel.variables := list(Variable.mapExpShallow(v, expandSlicedCrefsExp) for v in flatModel.variables); |
| 217 | 1211 | flatModel := FlatModel.mapEquations(flatModel, expandSlicedCrefsEq); | |
| 218 | 1211 | flatModel := FlatModel.mapAlgorithms(flatModel, expandSlicedCrefsAlg); | |
| 219 | 1211 | functions := FunctionTree.map(functions, expandSlicedCrefsFunction); | |
| 220 | end expandSlicedCrefs; | ||
| 221 | |||
| 222 | function addTrailingWholeIndices | ||
| 223 | "Add implicit trailing subscripts to array expressions. | ||
| 224 | E.g. for Real[10,2] a this will replace a[i] with a[i,:]." | ||
| 225 | input output Expression exp; | ||
| 226 | algorithm | ||
| 227 | exp := match exp | ||
| 228 | case Expression.CREF() | ||
| 229 | guard ComponentRef.hasImplicitTrailingIndex(exp.cref) | ||
| 230 | algorithm | ||
| 231 | 4 | exp.cref := ComponentRef.fillSubscripts(exp.cref); | |
| 232 | then exp; | ||
| 233 | |||
| 234 | else exp; | ||
| 235 | end match; | ||
| 236 | end addTrailingWholeIndices; | ||
| 237 | |||
| 238 | function expandSlicedCrefsExp | ||
| 239 | input output Expression exp; | ||
| 240 | algorithm | ||
| 241 | exp := match exp | ||
| 242 | case Expression.CREF() | ||
| 243 | guard ComponentRef.isSliced(exp.cref) | ||
| 244 | 1 | then expandSlicedCrefsExp2(exp.cref, exp.ty); | |
| 245 | |||
| 246 | else exp; | ||
| 247 | end match; | ||
| 248 | end expandSlicedCrefsExp; | ||
| 249 | |||
| 250 | function expandSlicedCrefsExp2 | ||
| 251 | input ComponentRef cref; | ||
| 252 | input Type ty; | ||
| 253 | output Expression outExp; | ||
| 254 | protected | ||
| 255 | ComponentRef cr; | ||
| 256 | list<tuple<InstNode, Expression>> iterators; | ||
| 257 | algorithm | ||
| 258 | 1 | (cr, iterators) := ComponentRef.iterate(cref); | |
| 259 | 1 | outExp := Expression.CALL( | |
| 260 | Call.TYPED_ARRAY_CONSTRUCTOR( | ||
| 261 | ty, | ||
| 262 | ComponentRef.variability(cref), | ||
| 263 | ComponentRef.purity(cref), | ||
| 264 | Expression.fromCref(cr), | ||
| 265 | iterators | ||
| 266 | ) | ||
| 267 | ); | ||
| 268 | end expandSlicedCrefsExp2; | ||
| 269 | |||
| 270 | function expandSlicedCrefsEq | ||
| 271 | input output Equation eq; | ||
| 272 | protected | ||
| 273 | Expression e1, e2; | ||
| 274 | Equation eq2; | ||
| 275 | algorithm | ||
| 276 | eq := match eq | ||
| 277 | case Equation.EQUALITY(rhs = e1) | ||
| 278 | algorithm | ||
| 279 | 146039 | e1:= Expression.map(e1, addTrailingWholeIndices); | |
| 280 | 146039 | e2 := Expression.map(e1, expandSlicedCrefsExp); | |
| 281 | |||
| 282 |
2/2✓ Branch 0 taken 109939 times.
✓ Branch 1 taken 36100 times.
|
146039 | if not referenceEq(e1, e2) then |
| 283 | 109939 | eq.rhs := e2; | |
| 284 | end if; | ||
| 285 | then | ||
| 286 | eq; | ||
| 287 | |||
| 288 | else | ||
| 289 | algorithm | ||
| 290 | 2242 | eq2 := Equation.mapExpShallow(eq, function Expression.map(func = addTrailingWholeIndices)); | |
| 291 | 2242 | then Equation.mapExpShallow(eq2, function Expression.map(func = expandSlicedCrefsExp)); | |
| 292 | end match; | ||
| 293 | end expandSlicedCrefsEq; | ||
| 294 | |||
| 295 | function expandSlicedCrefsAlg | ||
| 296 | input output Algorithm alg; | ||
| 297 | algorithm | ||
| 298 |
4/4✓ Branch 0 taken 57699 times.
✓ Branch 1 taken 9303 times.
✓ Branch 2 taken 57699 times.
✓ Branch 3 taken 9303 times.
|
67002 | alg.statements := list(Statement.map(s, expandSlicedCrefsStmt) for s in alg.statements); |
| 299 | end expandSlicedCrefsAlg; | ||
| 300 | |||
| 301 | function expandSlicedCrefsStmt | ||
| 302 | input output Statement stmt; | ||
| 303 | protected | ||
| 304 | Expression e1, e2; | ||
| 305 | algorithm | ||
| 306 | stmt := match stmt | ||
| 307 | local | ||
| 308 | Statement stmt2; | ||
| 309 | case Statement.ASSIGNMENT(rhs = e1) | ||
| 310 | algorithm | ||
| 311 | 84785 | stmt.lhs := Expression.map(stmt.lhs, addTrailingWholeIndices); | |
| 312 | 84785 | e1 := Expression.map(e1, addTrailingWholeIndices); | |
| 313 | 84785 | e2 := Expression.map(e1, expandSlicedCrefsExp); | |
| 314 | |||
| 315 |
2/2✓ Branch 0 taken 79333 times.
✓ Branch 1 taken 5452 times.
|
84785 | if not referenceEq(e1, e2) then |
| 316 | 79333 | stmt.rhs := e2; | |
| 317 | end if; | ||
| 318 | then | ||
| 319 | stmt; | ||
| 320 | |||
| 321 | else | ||
| 322 | algorithm | ||
| 323 | 7293 | stmt2 := Statement.mapExpShallow(stmt, function Expression.map(func = addTrailingWholeIndices)); | |
| 324 | 7293 | then Statement.mapExpShallow(stmt2, function Expression.map(func = expandSlicedCrefsExp)); | |
| 325 | end match; | ||
| 326 | end expandSlicedCrefsStmt; | ||
| 327 | |||
| 328 | function expandSlicedCrefsFunction | ||
| 329 | input Absyn.Path fnPath; | ||
| 330 | input output Function fn; | ||
| 331 | algorithm | ||
| 332 | 10931 | fn := Function.mapExp(fn, | |
| 333 | function Expression.map(func = expandSlicedCrefsExp), mapBody = false); | ||
| 334 | 10931 | fn := Function.mapBody(fn, expandSlicedCrefsAlg); | |
| 335 | end expandSlicedCrefsFunction; | ||
| 336 | |||
| 337 | type MergeNameMap = UnorderedMap<String, Absyn.ComponentRef>; | ||
| 338 | |||
| 339 | function makeMergeNameMap | ||
| 340 | output MergeNameMap nameMap = UnorderedMap.new<Absyn.ComponentRef>(stringHashDjb2, stringEq); | ||
| 341 | end makeMergeNameMap; | ||
| 342 | |||
| 343 | function mergeScalars | ||
| 344 | "Tries to merge components inside the given class into arrays. Components | ||
| 345 | can be merged if they have e.g. the same type, same prefixes, same | ||
| 346 | modifiers, etc." | ||
| 347 | input output InstNode node; | ||
| 348 | input Absyn.Path classPath; | ||
| 349 | input Boolean isRootClass; | ||
| 350 | input MergeNameMap nameMap = makeMergeNameMap(); | ||
| 351 | protected | ||
| 352 | SCode.Element elem; | ||
| 353 | algorithm | ||
| 354 |
2/2✓ Branch 1 taken 19607 times.
✓ Branch 2 taken 4 times.
|
19611 | if not Flags.isSet(Flags.MERGE_COMPONENTS) then |
| 355 | 19607 | return; | |
| 356 | end if; | ||
| 357 | |||
| 358 | 4 | elem := InstNode.definition(node); | |
| 359 | 4 | elem := mergeScalars2(elem, classPath, isRootClass, nameMap); | |
| 360 | 4 | node := InstNode.setDefinition(elem, node); | |
| 361 | 4 | execStat(getInstanceName()); | |
| 362 | end mergeScalars; | ||
| 363 | |||
| 364 | function mergeScalars2 | ||
| 365 | "Helper function to mergeScalars, does the actual merging." | ||
| 366 | input output SCode.Element cls; | ||
| 367 | input Absyn.Path classPath; | ||
| 368 | input Boolean isRootClass; | ||
| 369 | input MergeNameMap nameMap; | ||
| 370 | protected | ||
| 371 | SCode.ClassDef cdef; | ||
| 372 | list<SCode.Element> elems; | ||
| 373 | algorithm | ||
| 374 | () := match cls | ||
| 375 | case SCode.Element.CLASS(classDef = cdef as SCode.ClassDef.PARTS()) | ||
| 376 | algorithm | ||
| 377 | // Merge components. | ||
| 378 | 4 | elems := mergeScalars3(cdef.elementLst, nameMap); | |
| 379 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
|
10 | elems := list(mergeScalarsElement(e, nameMap) for e in elems); |
| 380 | 4 | cdef.elementLst := elems; | |
| 381 | // Replace references to merged components with their new names. | ||
| 382 | 4 | cdef.normalEquationLst := mergeScalarsEql(cdef.normalEquationLst, nameMap); | |
| 383 | 4 | cdef.initialEquationLst := mergeScalarsEql(cdef.initialEquationLst, nameMap); | |
| 384 | 4 | cdef.normalAlgorithmLst := mergeScalarsAlgs(cdef.normalAlgorithmLst, nameMap); | |
| 385 | 4 | cdef.initialAlgorithmLst := mergeScalarsAlgs(cdef.initialAlgorithmLst, nameMap); | |
| 386 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | cls.classDef := cdef; |
| 387 | |||
| 388 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if isRootClass then |
| 389 | 4 | System.writeFile(AbsynUtil.pathString(classPath) + "_merged_table.json", | |
| 390 | UnorderedMap.toJSON(nameMap, Util.id, Dump.printComponentRefStr)); | ||
| 391 | end if; | ||
| 392 | then | ||
| 393 | (); | ||
| 394 | |||
| 395 | else (); | ||
| 396 | end match; | ||
| 397 | end mergeScalars2; | ||
| 398 | |||
| 399 | function mergeScalars3 | ||
| 400 | "Helper function to mergeScalars2. Takes a list of elements and returns a | ||
| 401 | new list with components merged, as well as a map of the merged components' | ||
| 402 | old names to their new names." | ||
| 403 | input list<SCode.Element> elements; | ||
| 404 | input MergeNameMap nameMap; | ||
| 405 | output list<SCode.Element> outElements; | ||
| 406 | protected | ||
| 407 | list<list<SCode.Element>> mergeable; | ||
| 408 | SCode.Element merged_e; | ||
| 409 | Integer i = UnorderedMap.size(nameMap) + 1; | ||
| 410 | String prefix; | ||
| 411 | algorithm | ||
| 412 | // Find the groups of mergeable component. | ||
| 413 | 4 | (mergeable, outElements) := makeMergeMap(elements); | |
| 414 | |||
| 415 | // Merge each group of mergeable components. | ||
| 416 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | for el in mergeable loop |
| 417 | // The name of the merged component will be $LastIdentInTypeOfComponent + | ||
| 418 | // an index to ensure the name is unique. | ||
| 419 | 6 | prefix := "$" + AbsynUtil.pathLastIdent(SCodeUtil.getElementTypePath(listHead(el))); | |
| 420 | 6 | merged_e := mergeComponents(el, prefix + String(i), nameMap); | |
| 421 | 6 | i := i + 1; | |
| 422 | 6 | outElements := merged_e :: outElements; | |
| 423 | end for; | ||
| 424 | |||
| 425 | 4 | outElements := listReverseInPlace(outElements); | |
| 426 | end mergeScalars3; | ||
| 427 | |||
| 428 | function makeMergeMap | ||
| 429 | "Takes a list of elements and returns a list of mergeable component groups | ||
| 430 | and a list of all other unmergeable elements." | ||
| 431 | input list<SCode.Element> elements; | ||
| 432 | output list<list<SCode.Element>> mergeable = {}; | ||
| 433 | output list<SCode.Element> unmergeable = {}; | ||
| 434 | protected | ||
| 435 | type ElementList = list<SCode.Element>; | ||
| 436 | UnorderedMap<String, ElementList> merge_map; | ||
| 437 | list<list<SCode.Element>> grouped_elems; | ||
| 438 | |||
| 439 | function append_merge | ||
| 440 | input Option<list<SCode.Element>> oldValue; | ||
| 441 | input SCode.Element elem; | ||
| 442 | output list<SCode.Element> newValue; | ||
| 443 | algorithm | ||
| 444 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 6 times.
|
14 | if isSome(oldValue) then |
| 445 | 8 | SOME(newValue) := oldValue; | |
| 446 | else | ||
| 447 | newValue := {}; | ||
| 448 | end if; | ||
| 449 | |||
| 450 | newValue := elem :: newValue; | ||
| 451 | end append_merge; | ||
| 452 | algorithm | ||
| 453 | 4 | merge_map := UnorderedMap.new<ElementList>(stringHashDjb2, stringEq); | |
| 454 | |||
| 455 | // Group the components by their signature if they fulfill the requirements | ||
| 456 | // for being considered mergeable. | ||
| 457 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
|
18 | for e in elements loop |
| 458 | () := match e | ||
| 459 | case SCode.Element.COMPONENT() | ||
| 460 | guard isMergeableComponent(e) | ||
| 461 | algorithm | ||
| 462 | 14 | UnorderedMap.addUpdate(getComponentSignature(e), | |
| 463 | function append_merge(elem = e), merge_map); | ||
| 464 | then | ||
| 465 | (); | ||
| 466 | |||
| 467 | else | ||
| 468 | algorithm | ||
| 469 | unmergeable := e :: unmergeable; | ||
| 470 | then | ||
| 471 | (); | ||
| 472 | end match; | ||
| 473 | end for; | ||
| 474 | |||
| 475 | 4 | grouped_elems := UnorderedMap.valueList(merge_map); | |
| 476 | |||
| 477 | // Move single mergeable components to the list of unmergeables. | ||
| 478 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | for el in grouped_elems loop |
| 479 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if listLength(el) == 1 then |
| 480 | ✗ | unmergeable := listHead(el) :: unmergeable; | |
| 481 | else | ||
| 482 | 6 | mergeable := listReverseInPlace(el) :: mergeable; | |
| 483 | end if; | ||
| 484 | end for; | ||
| 485 | end makeMergeMap; | ||
| 486 | |||
| 487 | function isMergeableComponent | ||
| 488 | "Returns true if an element is a component that is considered to be | ||
| 489 | mergeable, otherwise false. A component is considered to be not mergeable | ||
| 490 | if it is e.g. a redeclare or inner/outer." | ||
| 491 | input SCode.Element element; | ||
| 492 | output Boolean isMergeable; | ||
| 493 | algorithm | ||
| 494 | isMergeable := match element | ||
| 495 | case SCode.Element.COMPONENT(attributes = SCode.Attributes.ATTR(arrayDims = {}), | ||
| 496 | prefixes = SCode.Prefixes.PREFIXES( | ||
| 497 | redeclarePrefix = SCode.Redeclare.NOT_REDECLARE(), | ||
| 498 | innerOuter = Absyn.InnerOuter.NOT_INNER_OUTER(), | ||
| 499 | replaceablePrefix = SCode.Replaceable.NOT_REPLACEABLE()), | ||
| 500 | condition = NONE()) | ||
| 501 |
2/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
|
14 | then isMergeableType(element.typeSpec) and isMergeableMod(element.modifications); |
| 502 | |||
| 503 | else false; | ||
| 504 | end match; | ||
| 505 | end isMergeableComponent; | ||
| 506 | |||
| 507 | function isMergeableMod | ||
| 508 | input SCode.Mod mod; | ||
| 509 | output Boolean mergeable; | ||
| 510 | algorithm | ||
| 511 | mergeable := match mod | ||
| 512 | case SCode.MOD(eachPrefix = SCode.Each.NOT_EACH()) | ||
| 513 | algorithm | ||
| 514 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 42 times.
|
70 | for m in mod.subModLst loop |
| 515 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
|
28 | if not isMergeableMod(m.mod) then |
| 516 | mergeable := false; | ||
| 517 | ✗ | return; | |
| 518 | end if; | ||
| 519 | end for; | ||
| 520 | then | ||
| 521 | true; | ||
| 522 | |||
| 523 | case SCode.NOMOD() then true; | ||
| 524 | else false; | ||
| 525 | end match; | ||
| 526 | end isMergeableMod; | ||
| 527 | |||
| 528 | function isMergeableType | ||
| 529 | input Absyn.TypeSpec ty; | ||
| 530 | output Boolean mergeable; | ||
| 531 | algorithm | ||
| 532 | mergeable := match ty | ||
| 533 | case Absyn.TPATH(arrayDim = NONE()) then true; | ||
| 534 | else false; | ||
| 535 | end match; | ||
| 536 | end isMergeableType; | ||
| 537 | |||
| 538 | function getComponentSignature | ||
| 539 | "Creates a signature string for a component which consists of the components | ||
| 540 | attributes, type, and modifiers, that can be used to group similar | ||
| 541 | components together." | ||
| 542 | input SCode.Element element; | ||
| 543 | output String signature; | ||
| 544 | protected | ||
| 545 | SCode.Prefixes prefs; | ||
| 546 | SCode.Attributes attrs; | ||
| 547 | Absyn.TypeSpec ty; | ||
| 548 | SCode.Mod mod; | ||
| 549 | algorithm | ||
| 550 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | SCode.Element.COMPONENT(prefixes = prefs, attributes = attrs, typeSpec = ty, |
| 551 | modifications = mod) := element; | ||
| 552 | |||
| 553 | 112 | signature := stringAppendList({ | |
| 554 | SCodeDump.visibilityStr(prefs.visibility), | ||
| 555 | SCodeDump.finalStr(prefs.finalPrefix), | ||
| 556 | SCodeDump.connectorTypeStr(attrs.connectorType), | ||
| 557 | SCodeDump.variabilityString(attrs.variability), | ||
| 558 | Dump.unparseDirectionSymbolStr(attrs.direction), | ||
| 559 | Dump.unparseTypeSpec(ty), | ||
| 560 | getModSignature(mod) | ||
| 561 | }); | ||
| 562 | end getComponentSignature; | ||
| 563 | |||
| 564 | function getModSignature | ||
| 565 | "Creates a signature string for a modifier that can be hashed in order to | ||
| 566 | group similar modifiers. The signature is similar to the string | ||
| 567 | representation of the modifier with the binding expressions removed, e.g.: | ||
| 568 | |||
| 569 | (x=3, y(start=1)=4, m(a=1)) => '(m(a=,),x=,y(start=,)=,)' | ||
| 570 | |||
| 571 | Submodifiers are also sorted by their names, so (x=3, y=4) and (y=4, x=3) | ||
| 572 | both have the signature '(x=,y=,)'." | ||
| 573 | input SCode.Mod mod; | ||
| 574 | input String name = ""; | ||
| 575 | output String signature; | ||
| 576 | protected | ||
| 577 | function sub_mod_lt | ||
| 578 | input SCode.SubMod m1; | ||
| 579 | input SCode.SubMod m2; | ||
| 580 | output Boolean res = m1.ident < m2.ident; | ||
| 581 | end sub_mod_lt; | ||
| 582 | |||
| 583 | list<String> strl = {}; | ||
| 584 | Boolean has_binding, has_submods; | ||
| 585 | algorithm | ||
| 586 | signature := match mod | ||
| 587 | case SCode.Mod.MOD() | ||
| 588 | algorithm | ||
| 589 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 12 times.
|
42 | has_binding := isSome(mod.binding); |
| 590 | 42 | has_submods := not listEmpty(mod.subModLst); | |
| 591 | |||
| 592 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
|
42 | if has_binding then |
| 593 | strl := "=" :: strl; | ||
| 594 | end if; | ||
| 595 | |||
| 596 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
|
42 | if has_submods then |
| 597 | strl := ")" :: strl; | ||
| 598 | |||
| 599 |
2/2✓ Branch 2 taken 28 times.
✓ Branch 3 taken 12 times.
|
40 | for m in List.sort(mod.subModLst, sub_mod_lt) loop |
| 600 | strl := "," :: strl; | ||
| 601 | 28 | strl := getModSignature(m.mod, m.ident) :: strl; | |
| 602 | end for; | ||
| 603 | |||
| 604 | strl := "(" :: strl; | ||
| 605 | end if; | ||
| 606 | |||
| 607 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | if has_binding or has_submods then |
| 608 | strl := name :: strl; | ||
| 609 | end if; | ||
| 610 | |||
| 611 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
|
42 | if SCodeUtil.finalBool(mod.finalPrefix) then |
| 612 | strl := "final " :: strl; | ||
| 613 | end if; | ||
| 614 | |||
| 615 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
|
42 | if SCodeUtil.eachBool(mod.eachPrefix) then |
| 616 | strl := "each " :: strl; | ||
| 617 | end if; | ||
| 618 | 42 | then | |
| 619 | stringAppendList(strl); | ||
| 620 | |||
| 621 | else ""; | ||
| 622 | end match; | ||
| 623 | end getModSignature; | ||
| 624 | |||
| 625 | function mergeComponents | ||
| 626 | "Merges a list of components into a single component." | ||
| 627 | input list<SCode.Element> components; | ||
| 628 | input String prefix; | ||
| 629 | input MergeNameMap nameMap; | ||
| 630 | output SCode.Element mergedComponent; | ||
| 631 | protected | ||
| 632 | Absyn.TypeSpec ty; | ||
| 633 | SCode.Prefixes prefs; | ||
| 634 | SCode.Attributes attrs; | ||
| 635 | SCode.Mod mod; | ||
| 636 | Integer i = 1; | ||
| 637 | String name; | ||
| 638 | Absyn.ComponentRef cref; | ||
| 639 | list<SCode.Mod> mods; | ||
| 640 | algorithm | ||
| 641 | // All components should have the same type and attributes, so take them | ||
| 642 | // from the first component in the list. | ||
| 643 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | SCode.Element.COMPONENT(typeSpec = ty, |
| 644 | prefixes = prefs, | ||
| 645 | attributes = attrs) := listHead(components); | ||
| 646 | |||
| 647 | // Add a dimension equal to the number of components. | ||
| 648 | 12 | attrs.arrayDims := {AbsynUtil.makeIntegerSubscript(listLength(components))}; | |
| 649 | |||
| 650 | // Merge the modifiers into a single modifier. | ||
| 651 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 6 times.
|
20 | mods := list(SCodeUtil.componentMod(c) for c in components); |
| 652 | 6 | mod := mergeMods(mods); | |
| 653 | |||
| 654 | 6 | mergedComponent := SCode.Element.COMPONENT( | |
| 655 | prefix, | ||
| 656 | prefs, | ||
| 657 | attrs, | ||
| 658 | ty, | ||
| 659 | mod, | ||
| 660 | SCode.noComment, | ||
| 661 | NONE(), | ||
| 662 | Absyn.dummyInfo | ||
| 663 | ); | ||
| 664 | |||
| 665 | // Add a mapping from old name to new name for each of the merged components. | ||
| 666 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
|
20 | for c in components loop |
| 667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | SCode.Element.COMPONENT(name = name) := c; |
| 668 | 28 | cref := Absyn.ComponentRef.CREF_IDENT(prefix, {AbsynUtil.makeIntegerSubscript(i)}); | |
| 669 | 14 | i := i + 1; | |
| 670 | 14 | UnorderedMap.addUnique(name, cref, nameMap); | |
| 671 | end for; | ||
| 672 | end mergeComponents; | ||
| 673 | |||
| 674 | function mergeMods | ||
| 675 | "Merges a list of modifiers into one modifier. All modifiers are assumed to | ||
| 676 | be equal with exception for binding expressions." | ||
| 677 | input list<SCode.Mod> mods; | ||
| 678 | output SCode.Mod mod; | ||
| 679 | protected | ||
| 680 | list<Absyn.Path> names; | ||
| 681 | list<list<Absyn.Exp>> bindings; | ||
| 682 | UnorderedMap<Absyn.Path, Absyn.Exp> binding_map; | ||
| 683 | algorithm | ||
| 684 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if listEmpty(mods) then |
| 685 | mod := SCode.Mod.NOMOD(); | ||
| 686 | ✗ | return; | |
| 687 | end if; | ||
| 688 | |||
| 689 | // Get the paths of all the modified elements. | ||
| 690 | 6 | mod := listHead(mods); | |
| 691 | 6 | names := getModNames(mod); | |
| 692 | 6 | bindings := List.fill({}, listLength(names)); | |
| 693 | |||
| 694 | // Collect the bindings from all modifiers. | ||
| 695 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 6 times.
|
20 | for m in listReverse(mods) loop |
| 696 | 14 | bindings := getModBindings(m, names, bindings); | |
| 697 | end for; | ||
| 698 | |||
| 699 | // Make a name => binding map. | ||
| 700 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
|
18 | binding_map := UnorderedMap.fromLists<Absyn.Exp>(names, |
| 701 | listReverse(Absyn.Exp.ARRAY(b) for b in bindings), | ||
| 702 | AbsynUtil.pathHash, AbsynUtil.pathEqual); | ||
| 703 | |||
| 704 | // Use one the modifiers as a template and replace the bindings in it with | ||
| 705 | // the merged bindings, in order to preserve 'each' and 'final'. | ||
| 706 | 6 | mod := mergeMods2(mod, binding_map); | |
| 707 | end mergeMods; | ||
| 708 | |||
| 709 | function getModNames | ||
| 710 | "Returns a list of the modified names in a modifier, e.g.: | ||
| 711 | (x = 4, y(start = 1) = 3, m(a = 2)) => {x, y, y.start, m.a}" | ||
| 712 | input SCode.Mod mod; | ||
| 713 | input list<String> name = {}; | ||
| 714 | input output list<Absyn.Path> names = {}; | ||
| 715 | algorithm | ||
| 716 | names := match mod | ||
| 717 | case SCode.Mod.MOD() | ||
| 718 | algorithm | ||
| 719 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 5 times.
|
17 | if isSome(mod.binding) then |
| 720 | 12 | names := makeModPath(name) :: names; | |
| 721 | end if; | ||
| 722 | |||
| 723 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 17 times.
|
28 | for m in mod.subModLst loop |
| 724 | 11 | names := getModNames(m.mod, m.ident :: name, names); | |
| 725 | end for; | ||
| 726 | then | ||
| 727 | names; | ||
| 728 | |||
| 729 | else names; | ||
| 730 | end match; | ||
| 731 | end getModNames; | ||
| 732 | |||
| 733 | function makeModPath | ||
| 734 | input list<String> name; | ||
| 735 | output Absyn.Path path; | ||
| 736 | algorithm | ||
| 737 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
|
24 | if listEmpty(name) then |
| 738 | // Use $ to indicate an empty path since paths can't be empty. | ||
| 739 | path := Absyn.Path.IDENT("$"); | ||
| 740 | else | ||
| 741 | 22 | path := AbsynUtil.stringListPathReversed(name); | |
| 742 | end if; | ||
| 743 | end makeModPath; | ||
| 744 | |||
| 745 | function mergeMods2 | ||
| 746 | "Helper function to mergeMods, replaces bindings in the given modifier with | ||
| 747 | the merged bindings." | ||
| 748 | input output SCode.Mod mod; | ||
| 749 | input UnorderedMap<Absyn.Path, Absyn.Exp> bindingMap; | ||
| 750 | input list<String> name = {}; | ||
| 751 | protected | ||
| 752 | Absyn.Exp new_binding; | ||
| 753 | list<SCode.SubMod> submods = {}; | ||
| 754 | algorithm | ||
| 755 | () := match mod | ||
| 756 | case SCode.Mod.MOD() | ||
| 757 | algorithm | ||
| 758 | // If the modifier has a binding expression, look up the new binding | ||
| 759 | // in the map and replace it. | ||
| 760 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 5 times.
|
17 | if isSome(mod.binding) then |
| 761 | 12 | new_binding := UnorderedMap.getOrFail(makeModPath(name), bindingMap); | |
| 762 | 12 | mod.binding := SOME(new_binding); | |
| 763 | end if; | ||
| 764 | |||
| 765 | // Recursively do the same to the submodifiers. | ||
| 766 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
|
17 | if not listEmpty(mod.subModLst) then |
| 767 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5 times.
|
16 | for m in mod.subModLst loop |
| 768 | 22 | m.mod := mergeMods2(m.mod, bindingMap, m.ident :: name); | |
| 769 | submods := m :: submods; | ||
| 770 | end for; | ||
| 771 | |||
| 772 | 5 | mod.subModLst := listReverseInPlace(submods); | |
| 773 | end if; | ||
| 774 | then | ||
| 775 | (); | ||
| 776 | |||
| 777 | else (); | ||
| 778 | end match; | ||
| 779 | end mergeMods2; | ||
| 780 | |||
| 781 | function getModBindings | ||
| 782 | "Looks up the named bindings in a modifier and appends them to the binding | ||
| 783 | expression lists." | ||
| 784 | input SCode.Mod mod; | ||
| 785 | input list<Absyn.Path> names; | ||
| 786 | input output list<list<Absyn.Exp>> bindings; | ||
| 787 | protected | ||
| 788 | list<Absyn.Exp> mod_bindings = {}; | ||
| 789 | algorithm | ||
| 790 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 14 times.
|
44 | for name in names loop |
| 791 | 30 | mod_bindings := lookupModBinding(name, mod) :: mod_bindings; | |
| 792 | end for; | ||
| 793 | |||
| 794 |
7/8✓ Branch 0 taken 30 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 14 times.
|
44 | bindings := list(cons(e1, e2) threaded for e1 in mod_bindings, e2 in bindings); |
| 795 | end getModBindings; | ||
| 796 | |||
| 797 | function lookupModBinding | ||
| 798 | "Looks up the binding expression for the modifier given by the path." | ||
| 799 | input Absyn.Path name; | ||
| 800 | input SCode.Mod mod; | ||
| 801 | output Absyn.Exp binding; | ||
| 802 | algorithm | ||
| 803 |
3/6✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 30 times.
|
30 | SCode.Mod.MOD(binding = SOME(binding)) := lookupMod(name, mod); |
| 804 | end lookupModBinding; | ||
| 805 | |||
| 806 | function lookupMod | ||
| 807 | "Looks up the modifier given by the path." | ||
| 808 | input Absyn.Path name; | ||
| 809 | input SCode.Mod mod; | ||
| 810 | output SCode.Mod outMod; | ||
| 811 | algorithm | ||
| 812 | outMod := match name | ||
| 813 | case Absyn.Path.IDENT() | ||
| 814 | // $ means an empty path, return the given modifier in that case. | ||
| 815 | // Otherwise look the name up in the modifier. | ||
| 816 |
3/4✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
|
30 | then if name.name == "$" then mod else SCodeUtil.lookupModInMod(name.name, mod); |
| 817 | |||
| 818 | case Absyn.Path.QUALIFIED() | ||
| 819 | algorithm | ||
| 820 | ✗ | outMod := SCodeUtil.lookupModInMod(name.name, mod); | |
| 821 | ✗ | then | |
| 822 | lookupMod(name.path, outMod); | ||
| 823 | end match; | ||
| 824 | end lookupMod; | ||
| 825 | |||
| 826 | function mergeScalarsElement | ||
| 827 | input output SCode.Element element; | ||
| 828 | input MergeNameMap nameMap; | ||
| 829 | algorithm | ||
| 830 | () := match element | ||
| 831 | case SCode.Element.EXTENDS() | ||
| 832 | algorithm | ||
| 833 | ✗ | element.modifications := mergeScalarsMod(element.modifications, nameMap); | |
| 834 | then | ||
| 835 | (); | ||
| 836 | |||
| 837 | case SCode.Element.COMPONENT() | ||
| 838 | algorithm | ||
| 839 | 6 | element.modifications := mergeScalarsMod(element.modifications, nameMap); | |
| 840 | then | ||
| 841 | (); | ||
| 842 | |||
| 843 | else (); | ||
| 844 | end match; | ||
| 845 | end mergeScalarsElement; | ||
| 846 | |||
| 847 | function mergeScalarsEql | ||
| 848 | "Updates the names of merged components in a list of equations." | ||
| 849 | input output list<SCode.Equation> eql; | ||
| 850 | input MergeNameMap nameMap; | ||
| 851 | algorithm | ||
| 852 | 8 | eql := SCodeUtil.mapEquationsList(eql, function mergeScalarsEq(nameMap = nameMap)); | |
| 853 | end mergeScalarsEql; | ||
| 854 | |||
| 855 | function mergeScalarsEq | ||
| 856 | "Updates the names of merged components in an equation." | ||
| 857 | input output SCode.Equation eq; | ||
| 858 | input MergeNameMap nameMap; | ||
| 859 | algorithm | ||
| 860 | 1 | eq := SCodeUtil.mapEquationExps(eq, function mergeScalarsExps(nameMap = nameMap)); | |
| 861 | |||
| 862 | () := match eq | ||
| 863 | case SCode.Equation.EQ_CONNECT() | ||
| 864 | algorithm | ||
| 865 | ✗ | eq.crefLeft := mergeScalarsCref(eq.crefLeft, nameMap); | |
| 866 | ✗ | eq.crefRight := mergeScalarsCref(eq.crefRight, nameMap); | |
| 867 | then | ||
| 868 | (); | ||
| 869 | |||
| 870 | else (); | ||
| 871 | end match; | ||
| 872 | end mergeScalarsEq; | ||
| 873 | |||
| 874 | function mergeScalarsMod | ||
| 875 | input output SCode.Mod mod; | ||
| 876 | input MergeNameMap nameMap; | ||
| 877 | algorithm | ||
| 878 | () := match mod | ||
| 879 | case SCode.Mod.MOD() | ||
| 880 | algorithm | ||
| 881 | 34 | mod.binding := Util.applyOption(mod.binding, function mergeScalarsExps(nameMap = nameMap)); | |
| 882 |
4/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 17 times.
|
45 | mod.subModLst := list(mergeScalarsSubMod(m, nameMap) for m in mod.subModLst); |
| 883 | then | ||
| 884 | (); | ||
| 885 | |||
| 886 | else (); | ||
| 887 | end match; | ||
| 888 | end mergeScalarsMod; | ||
| 889 | |||
| 890 | function mergeScalarsSubMod | ||
| 891 | input output SCode.SubMod mod; | ||
| 892 | input MergeNameMap nameMap; | ||
| 893 | algorithm | ||
| 894 | 11 | mod.mod := mergeScalarsMod(mod.mod, nameMap); | |
| 895 | end mergeScalarsSubMod; | ||
| 896 | |||
| 897 | function mergeScalarsExps | ||
| 898 | "Updates the names of merged components in an expression." | ||
| 899 | input output Absyn.Exp exp; | ||
| 900 | input MergeNameMap nameMap; | ||
| 901 | algorithm | ||
| 902 | 16 | exp := AbsynUtil.traverseExp(exp, mergeScalarsExp, nameMap); | |
| 903 | end mergeScalarsExps; | ||
| 904 | |||
| 905 | function mergeScalarsExp | ||
| 906 | input output Absyn.Exp exp; | ||
| 907 | input output MergeNameMap nameMap; | ||
| 908 | algorithm | ||
| 909 | () := match exp | ||
| 910 | case Absyn.Exp.CREF() | ||
| 911 | guard not AbsynUtil.crefIsWild(exp.componentRef) | ||
| 912 | algorithm | ||
| 913 | 8 | exp.componentRef := mergeScalarsCref(exp.componentRef, nameMap); | |
| 914 | then | ||
| 915 | (); | ||
| 916 | |||
| 917 | else (); | ||
| 918 | end match; | ||
| 919 | end mergeScalarsExp; | ||
| 920 | |||
| 921 | function mergeScalarsCref | ||
| 922 | "Updates the names of a component reference if it refers to a merged component." | ||
| 923 | input output Absyn.ComponentRef cref; | ||
| 924 | input MergeNameMap nameMap; | ||
| 925 | protected | ||
| 926 | Option<Absyn.ComponentRef> repl_ocr; | ||
| 927 | Absyn.ComponentRef repl_cr; | ||
| 928 | list<Absyn.Subscript> subs; | ||
| 929 | algorithm | ||
| 930 | // Look up the first part of the cref in the name map. | ||
| 931 | 8 | repl_ocr := UnorderedMap.get(AbsynUtil.crefFirstIdent(cref), nameMap); | |
| 932 | |||
| 933 | // If a replacement was found... | ||
| 934 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | if isSome(repl_ocr) then |
| 935 | 8 | SOME(repl_cr) := repl_ocr; | |
| 936 | // The new name has a subscript that needs to be merged with any existing subscripts. | ||
| 937 | 8 | subs := AbsynUtil.crefFirstSubs(cref); | |
| 938 | |||
| 939 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if not listEmpty(subs) then |
| 940 | ✗ | subs := listAppend(AbsynUtil.crefFirstSubs(repl_cr), subs); | |
| 941 | ✗ | repl_cr := AbsynUtil.crefSetLastSubs(repl_cr, subs); | |
| 942 | end if; | ||
| 943 | |||
| 944 | // Replace the first part of the cref with the new part. | ||
| 945 | 8 | cref := AbsynUtil.crefReplaceFirst(cref, repl_cr); | |
| 946 | end if; | ||
| 947 | end mergeScalarsCref; | ||
| 948 | |||
| 949 | function mergeScalarsAlgs | ||
| 950 | "Updates the names of merged components in a list of algorithm sections." | ||
| 951 | input output list<SCode.AlgorithmSection> algs; | ||
| 952 | input MergeNameMap nameMap; | ||
| 953 | algorithm | ||
| 954 |
4/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 8 times.
|
9 | algs := list(SCodeUtil.mapAlgorithmStatements(a, |
| 955 | function mergeScalarsStmt(nameMap = nameMap)) for a in algs); | ||
| 956 | end mergeScalarsAlgs; | ||
| 957 | |||
| 958 | function mergeScalarsStmt | ||
| 959 | "Updates the names of merged components in a statement." | ||
| 960 | input output SCode.Statement stmt; | ||
| 961 | input MergeNameMap nameMap; | ||
| 962 | algorithm | ||
| 963 | 1 | stmt := SCodeUtil.mapStatementExps(stmt, function mergeScalarsExps(nameMap = nameMap)); | |
| 964 | end mergeScalarsStmt; | ||
| 965 | |||
| 966 | function mergeScalarsComponentBindings | ||
| 967 | input InstNode node; | ||
| 968 | input MergeNameMap nameMap; | ||
| 969 | protected | ||
| 970 | Class cls; | ||
| 971 | ClassTree cls_tree; | ||
| 972 | algorithm | ||
| 973 | ✗ | cls := InstNode.getClass(node); | |
| 974 | ✗ | cls_tree := Class.classTree(cls); | |
| 975 | ✗ | ClassTree.applyComponents(cls_tree, function mergeScalarsComponentBinding(nameMap = nameMap)); | |
| 976 | ✗ | cls := Class.setClassTree(cls_tree, cls); | |
| 977 | ✗ | InstNode.updateClass(cls, node); | |
| 978 | end mergeScalarsComponentBindings; | ||
| 979 | |||
| 980 | function mergeScalarsComponentBinding | ||
| 981 | input InstNode node; | ||
| 982 | input MergeNameMap nameMap; | ||
| 983 | protected | ||
| 984 | Component comp; | ||
| 985 | algorithm | ||
| 986 | ✗ | if not InstNode.isComponent(node) then | |
| 987 | ✗ | return; | |
| 988 | end if; | ||
| 989 | |||
| 990 | ✗ | comp := InstNode.component(node); | |
| 991 | |||
| 992 | () := match comp | ||
| 993 | case Component.COMPONENT_DEF() | ||
| 994 | algorithm | ||
| 995 | ✗ | comp.definition := mergeScalarsElement(comp.definition, nameMap); | |
| 996 | ✗ | InstNode.updateComponent(comp, node); | |
| 997 | then | ||
| 998 | (); | ||
| 999 | |||
| 1000 | else (); | ||
| 1001 | end match; | ||
| 1002 | end mergeScalarsComponentBinding; | ||
| 1003 | |||
| 1004 | function createExtractorModel | ||
| 1005 | input FlatModel flatModel; | ||
| 1006 | input FunctionTree funcs; | ||
| 1007 | output FlatModel extractorModel = flatModel; | ||
| 1008 | output FunctionTree outFuncs = funcs; | ||
| 1009 | protected | ||
| 1010 | list<Variable> top_level_connectors, flows, inputs; | ||
| 1011 | Function fn_template; | ||
| 1012 | Integer index = 0; | ||
| 1013 | list<Equation> eqs = {}; | ||
| 1014 | Equation eq; | ||
| 1015 | list<Expression> args; | ||
| 1016 | algorithm | ||
| 1017 | ✗ | (top_level_connectors, flows, inputs) := collectExtractorModelVariables(flatModel.variables); | |
| 1018 | ✗ | fn_template := createExtractorModelDummyFn(top_level_connectors); | |
| 1019 | ✗ | args := list(Expression.fromCref(Variable.name(c)) for c in top_level_connectors); | |
| 1020 | |||
| 1021 | ✗ | for f in flows loop | |
| 1022 | ✗ | (eq, outFuncs, index) := createExtractorModelDummyEq(f, "flow", fn_template, args, outFuncs, index); | |
| 1023 | eqs := eq :: eqs; | ||
| 1024 | end for; | ||
| 1025 | |||
| 1026 | ✗ | for i in inputs loop | |
| 1027 | ✗ | (eq, outFuncs, index) := createExtractorModelDummyEq(i, "input", fn_template, args, outFuncs, index); | |
| 1028 | eqs := eq :: eqs; | ||
| 1029 | end for; | ||
| 1030 | |||
| 1031 | ✗ | eqs := listReverseInPlace(eqs); | |
| 1032 | ✗ | extractorModel.equations := listAppend(extractorModel.equations, eqs); | |
| 1033 | end createExtractorModel; | ||
| 1034 | |||
| 1035 | function collectExtractorModelVariables | ||
| 1036 | input list<Variable> vars; | ||
| 1037 | output list<Variable> topLevelConnectorVars = {}; | ||
| 1038 | output list<Variable> flowVars = {}; | ||
| 1039 | output list<Variable> inputVars = {}; | ||
| 1040 | protected | ||
| 1041 | InstNode top_node; | ||
| 1042 | algorithm | ||
| 1043 | ✗ | for var in listReverse(vars) loop | |
| 1044 | ✗ | if not ComponentRef.isSimple(var.name) then | |
| 1045 | ✗ | top_node := ComponentRef.node(ComponentRef.last(var.name)); | |
| 1046 | |||
| 1047 | ✗ | if InstNode.isConnector(top_node) and InstNode.isPublic(top_node) then | |
| 1048 | topLevelConnectorVars := var :: topLevelConnectorVars; | ||
| 1049 | |||
| 1050 | ✗ | if Variable.isFlow(var) then | |
| 1051 | flowVars := var :: flowVars; | ||
| 1052 | elseif Variable.isInput(var) then | ||
| 1053 | inputVars := var :: flowVars; | ||
| 1054 | end if; | ||
| 1055 | end if; | ||
| 1056 | end if; | ||
| 1057 | end for; | ||
| 1058 | end collectExtractorModelVariables; | ||
| 1059 | |||
| 1060 | constant Absyn.TypeSpec REAL_TYPE_SPEC = Absyn.TypeSpec.TPATH(Absyn.Path.IDENT("Real"), NONE()); | ||
| 1061 | |||
| 1062 | function createExtractorModelDummyFn | ||
| 1063 | input list<Variable> connectors; | ||
| 1064 | output Function fn; | ||
| 1065 | protected | ||
| 1066 | SCode.ClassDef cdef; | ||
| 1067 | SCode.Element output_param, elem; | ||
| 1068 | InstNode fn_node; | ||
| 1069 | list<SCode.Element> params; | ||
| 1070 | SCode.Mod output_binding; | ||
| 1071 | SCode.Comment cmt; | ||
| 1072 | algorithm | ||
| 1073 | ✗ | output_binding := SCodeUtil.makeMod(binding = SOME(Absyn.Exp.INTEGER(0))); | |
| 1074 | ✗ | output_param := SCode.Element.COMPONENT("dummy", SCode.defaultPrefixes, SCode.defaultOutputAttr, | |
| 1075 | REAL_TYPE_SPEC, output_binding, SCode.noComment, NONE(), Absyn.dummyInfo); | ||
| 1076 | ✗ | params := listAppend(list(createExtractorModelDummyFnInput(c) for c in connectors), {output_param}); | |
| 1077 | |||
| 1078 | ✗ | cdef := SCode.ClassDef.PARTS( | |
| 1079 | params, | ||
| 1080 | {}, | ||
| 1081 | {}, | ||
| 1082 | {}, | ||
| 1083 | {}, | ||
| 1084 | {}, | ||
| 1085 | {}, | ||
| 1086 | NONE() | ||
| 1087 | ); | ||
| 1088 | |||
| 1089 | ✗ | cmt := SCode.COMMENT(SOME(SCode.Annotation.ANNOTATION(SCodeUtil.makeMod(subMods = | |
| 1090 | {SCode.SubMod.NAMEMOD("Inline", SCodeUtil.makeMod(binding = SOME(Absyn.Exp.BOOL(false))))}))), NONE()); | ||
| 1091 | |||
| 1092 | ✗ | elem := SCode.Element.CLASS( | |
| 1093 | "dummy", | ||
| 1094 | SCode.defaultPrefixes, | ||
| 1095 | SCode.Encapsulated.NOT_ENCAPSULATED(), | ||
| 1096 | SCode.Partial.NOT_PARTIAL(), | ||
| 1097 | SCode.Restriction.R_FUNCTION(SCode.FunctionRestriction.FR_NORMAL_FUNCTION(Absyn.FunctionPurity.PURE())), | ||
| 1098 | cdef, | ||
| 1099 | cmt, | ||
| 1100 | Absyn.dummyInfo | ||
| 1101 | ); | ||
| 1102 | |||
| 1103 | ✗ | fn_node := InstNode.new(elem, InstNode.EMPTY_NODE()); | |
| 1104 | ✗ | fn_node := Function.instFunctionNode(fn_node, NFInstContext.FUNCTION, Absyn.dummyInfo); | |
| 1105 | ✗ | fn :: _ := Function.typeNodeCache(fn_node); | |
| 1106 | end createExtractorModelDummyFn; | ||
| 1107 | |||
| 1108 | function createExtractorModelDummyFnInput | ||
| 1109 | input Variable var; | ||
| 1110 | output SCode.Element inputElem; | ||
| 1111 | algorithm | ||
| 1112 | ✗ | inputElem := SCode.Element.COMPONENT( | |
| 1113 | ComponentRef.toFlatString(var.name, BaseModelica.defaultFormat), | ||
| 1114 | SCode.defaultPrefixes, | ||
| 1115 | SCode.defaultInputAttr, | ||
| 1116 | REAL_TYPE_SPEC, | ||
| 1117 | SCode.Mod.NOMOD(), | ||
| 1118 | SCode.noComment, | ||
| 1119 | NONE(), | ||
| 1120 | Absyn.dummyInfo | ||
| 1121 | ); | ||
| 1122 | end createExtractorModelDummyFnInput; | ||
| 1123 | |||
| 1124 | function createExtractorModelDummyEq | ||
| 1125 | input Variable var; | ||
| 1126 | input String varType; | ||
| 1127 | input Function fn; | ||
| 1128 | input list<Expression> args; | ||
| 1129 | output Equation eq; | ||
| 1130 | input output FunctionTree funcs; | ||
| 1131 | input output Integer index; | ||
| 1132 | protected | ||
| 1133 | Function indexed_fn; | ||
| 1134 | Absyn.Path fn_name; | ||
| 1135 | DAE.ElementSource src = DAE.emptyElementSource; | ||
| 1136 | String var_name; | ||
| 1137 | algorithm | ||
| 1138 | while true loop | ||
| 1139 | ✗ | index := index + 1; | |
| 1140 | ✗ | fn_name := Absyn.Path.IDENT("f" + String(index)); | |
| 1141 | |||
| 1142 | ✗ | if not FunctionTree.hasKey(funcs, fn_name) then | |
| 1143 | break; | ||
| 1144 | end if; | ||
| 1145 | end while; | ||
| 1146 | |||
| 1147 | ✗ | indexed_fn := Function.setName(fn_name, fn); | |
| 1148 | ✗ | var_name := ComponentRef.toString(Variable.name(var)); | |
| 1149 | ✗ | src := ElementSource.addCommentToSource(src, | |
| 1150 | SOME(SCode.Comment.COMMENT(NONE(), SOME("Dummy equation for " + var_name + " " + varType + " variable")))); | ||
| 1151 | |||
| 1152 | ✗ | eq := Equation.makeEquality( | |
| 1153 | Expression.REAL(0), | ||
| 1154 | Expression.CALL(Call.makeTypedCall(indexed_fn, args, Variability.CONTINUOUS, Purity.PURE)), | ||
| 1155 | Type.REAL(), | ||
| 1156 | src, | ||
| 1157 | InstNode.fromHandle(fn.node) | ||
| 1158 | ); | ||
| 1159 | |||
| 1160 | ✗ | funcs := FunctionTree.add(funcs, fn_name, indexed_fn); | |
| 1161 | end createExtractorModelDummyEq; | ||
| 1162 | |||
| 1163 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 1164 | end NFInstUtil; | ||
| 1165 |