OMCompiler/Compiler/NFFrontEnd/NFClassTree.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 NFClassTree | ||
| 37 | import NFInstNode.InstNode; | ||
| 38 | import NFInstNode; | ||
| 39 | import SCode; | ||
| 40 | import NFType.Type; | ||
| 41 | import Mutable; | ||
| 42 | import NFModifier.Modifier; | ||
| 43 | import Import = NFImport; | ||
| 44 | import NFBuiltin; | ||
| 45 | import DuplicateTree = NFDuplicateTree; | ||
| 46 | import UnorderedMap; | ||
| 47 | |||
| 48 | protected | ||
| 49 | import Absyn; | ||
| 50 | import Array; | ||
| 51 | import Error; | ||
| 52 | import Flags; | ||
| 53 | import MetaModelica.Dangerous.*; | ||
| 54 | import Class = NFClass; | ||
| 55 | import Component = NFComponent; | ||
| 56 | import Inst = NFInst; | ||
| 57 | import List; | ||
| 58 | import Lookup = NFLookup; | ||
| 59 | import SCodeDump; | ||
| 60 | import SCodeUtil; | ||
| 61 | import NFInstNode.InstNodeType; | ||
| 62 | import Restriction = NFRestriction; | ||
| 63 | import LookupTree = NFLookupTree; | ||
| 64 | |||
| 65 | public | ||
| 66 | constant ClassTree EMPTY = ClassTree.PARTIAL_TREE(LookupTree.EMPTY(), | ||
| 67 | listArray({}), listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY()); | ||
| 68 | constant ClassTree EMPTY_FLAT = ClassTree.FLAT_TREE(LookupTree.EMPTY(), | ||
| 69 | listArray({}), listArray({}), listArray({}), DuplicateTree.EMPTY()); | ||
| 70 | |||
| 71 | type LookupEntry = LookupTree.Entry; | ||
| 72 | type LookupTable = UnorderedMap<String, LookupEntry>; | ||
| 73 | |||
| 74 | uniontype ClassTree | ||
| 75 | record PARTIAL_TREE | ||
| 76 | "A partial tree allows lookup of local classes and imported elements." | ||
| 77 | LookupTree.Tree tree; | ||
| 78 | array<InstNode> classes; | ||
| 79 | array<InstNode> components; | ||
| 80 | array<InstNode> exts; | ||
| 81 | array<Import> imports; | ||
| 82 | DuplicateTree.Tree duplicates; | ||
| 83 | end PARTIAL_TREE; | ||
| 84 | |||
| 85 | record EXPANDED_TREE | ||
| 86 | "Like partial tree, but the lookup tree is populated with all named | ||
| 87 | elements. The elements have not yet been added to the arrays though, so | ||
| 88 | lookup is still restricted to local classes and imported elements." | ||
| 89 | LookupTree.Tree tree; | ||
| 90 | array<InstNode> classes; | ||
| 91 | array<InstNode> components; | ||
| 92 | array<InstNode> exts; | ||
| 93 | array<Import> imports; | ||
| 94 | DuplicateTree.Tree duplicates; | ||
| 95 | end EXPANDED_TREE; | ||
| 96 | |||
| 97 | record INSTANTIATED_TREE | ||
| 98 | "Allows lookup of both local and inherited elements." | ||
| 99 | LookupTree.Tree tree; | ||
| 100 | array<Mutable<InstNode>> classes; | ||
| 101 | array<Mutable<InstNode>> components; | ||
| 102 | list<Integer> localComponents; | ||
| 103 | array<InstNode> exts; | ||
| 104 | array<Import> imports; | ||
| 105 | DuplicateTree.Tree duplicates; | ||
| 106 | end INSTANTIATED_TREE; | ||
| 107 | |||
| 108 | record FLAT_TREE | ||
| 109 | "A flattened version of an instantiated tree." | ||
| 110 | LookupTree.Tree tree; | ||
| 111 | array<InstNode> classes; | ||
| 112 | array<InstNode> components; | ||
| 113 | array<Import> imports; | ||
| 114 | DuplicateTree.Tree duplicates; | ||
| 115 | end FLAT_TREE; | ||
| 116 | |||
| 117 | record EMPTY_TREE | ||
| 118 | end EMPTY_TREE; | ||
| 119 | |||
| 120 | function fromSCode | ||
| 121 | "Creates a new class tree from a list of SCode elements. Imports are not | ||
| 122 | added to the lookup tree here to avoid dependency issues and should | ||
| 123 | instead be initialized by calling initImports once the class tree has | ||
| 124 | been added to the node it belongs to." | ||
| 125 | input list<SCode.Element> elements; | ||
| 126 | input Boolean isClassExtends; | ||
| 127 | input InstNode parent; | ||
| 128 | output ClassTree tree; | ||
| 129 | protected | ||
| 130 | LookupTree.Tree ltree; | ||
| 131 | LookupTree.Entry lentry; | ||
| 132 | Integer clsc, compc, extc; | ||
| 133 | array<InstNode> clss, comps, exts; | ||
| 134 | Integer cls_idx = 0, ext_idx = 0, comp_idx = 0; | ||
| 135 | DuplicateTree.Tree dups; | ||
| 136 | list<Import> imps = {}; | ||
| 137 | SourceInfo info; | ||
| 138 | algorithm | ||
| 139 | 79606 | ltree := LookupTree.new(); | |
| 140 | |||
| 141 | // Count the different types of elements. | ||
| 142 | 79606 | (clsc, compc, extc) := countElements(elements); | |
| 143 | |||
| 144 | // If the class is a class extends, reserve space for the extends. | ||
| 145 |
2/2✓ Branch 0 taken 3507 times.
✓ Branch 1 taken 76099 times.
|
79606 | if isClassExtends then |
| 146 | 3507 | extc := extc + 1; | |
| 147 | end if; | ||
| 148 | |||
| 149 | // Preallocate arrays for the elements. We can't do this for imports | ||
| 150 | // though, since an import clause might import multiple elements. | ||
| 151 | 79606 | clss := arrayCreateNoInit(clsc, InstNode.EMPTY_NODE()); | |
| 152 | 79606 | comps := arrayCreateNoInit(compc + extc, InstNode.EMPTY_NODE()); | |
| 153 | 79606 | exts := arrayCreateNoInit(extc, InstNode.EMPTY_NODE()); | |
| 154 | 79606 | dups := DuplicateTree.new(); | |
| 155 | // Make a temporary class tree so we can do lookup for error reporting. | ||
| 156 | 79606 | tree := PARTIAL_TREE(ltree, clss, comps, exts, listArray({}), dups); | |
| 157 | |||
| 158 | // If the class is a class extends, fill in the first extends with an | ||
| 159 | // empty node so we don't have unassigned memory after this step. | ||
| 160 |
2/2✓ Branch 0 taken 3507 times.
✓ Branch 1 taken 76099 times.
|
79606 | if isClassExtends then |
| 161 | 3507 | exts[1] := InstNode.EMPTY_NODE(); | |
| 162 | 3507 | comps[1] := InstNode.REF_NODE(1); | |
| 163 | ext_idx := ext_idx + 1; | ||
| 164 | comp_idx := comp_idx + 1; | ||
| 165 | end if; | ||
| 166 | |||
| 167 |
6/7✓ Branch 0 taken 986789 times.
✓ Branch 1 taken 264178 times.
✓ Branch 2 taken 44932 times.
✓ Branch 3 taken 12554 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1308453 times.
✓ Branch 6 taken 79604 times.
|
1388057 | for e in elements loop |
| 168 | () := match e | ||
| 169 | // A class, add it to the class array and add an entry in the lookup tree. | ||
| 170 | case SCode.CLASS() | ||
| 171 | algorithm | ||
| 172 | 986789 | cls_idx := cls_idx + 1; | |
| 173 | 986789 | arrayUpdateNoBoundsChecking(clss, cls_idx, InstNode.newClass(e, parent)); | |
| 174 | 986789 | lentry := LookupTree.Entry.CLASS(cls_idx); | |
| 175 | 986789 | ltree := addLocalElement(e.name, lentry, tree, ltree); | |
| 176 | |||
| 177 | // If the class is an element redeclare, add an entry in the duplicate | ||
| 178 | // tree so we can check later that it actually redeclares something. | ||
| 179 |
4/4✓ Branch 1 taken 982915 times.
✓ Branch 2 taken 3872 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 982913 times.
|
986787 | if SCodeUtil.isElementRedeclare(e) or SCodeUtil.isClassExtends(e) then |
| 180 | 3874 | dups := DuplicateTree.add(dups, e.name, DuplicateTree.newRedeclare(lentry)); | |
| 181 | end if; | ||
| 182 | then | ||
| 183 | (); | ||
| 184 | |||
| 185 | // A component, add it to the component array but don't add an entry | ||
| 186 | // in the lookup tree. We need to preserve the components' order, but | ||
| 187 | // won't know their actual indices until we've expanded the extends. | ||
| 188 | // We don't really need to be able to look up components until after | ||
| 189 | // that happens, so we add them to the lookup tree later instead. | ||
| 190 | case SCode.COMPONENT() | ||
| 191 | algorithm | ||
| 192 | 264178 | comp_idx := comp_idx + 1; | |
| 193 | 264178 | arrayUpdateNoBoundsChecking(comps, comp_idx, InstNode.newComponent(e)); | |
| 194 | then | ||
| 195 | (); | ||
| 196 | |||
| 197 | // An extends clause, add it to the list of extends, and also add a | ||
| 198 | // reference in the component array so we can preserve the order of | ||
| 199 | // components. | ||
| 200 | case SCode.EXTENDS() | ||
| 201 | algorithm | ||
| 202 | 44932 | ext_idx := ext_idx + 1; | |
| 203 | 44932 | arrayUpdateNoBoundsChecking(exts, ext_idx, InstNode.newExtends(e, parent)); | |
| 204 | 44932 | comp_idx := comp_idx + 1; | |
| 205 | 44932 | arrayUpdateNoBoundsChecking(comps, comp_idx, InstNode.REF_NODE(ext_idx)); | |
| 206 | then | ||
| 207 | (); | ||
| 208 | |||
| 209 | // An import, save it as it is and deal with it in initImports later. | ||
| 210 | case SCode.IMPORT() | ||
| 211 | algorithm | ||
| 212 | 12554 | imps := Import.UNRESOLVED_IMPORT(e.imp, InstNode.scopeRef(parent), e.info) :: imps; | |
| 213 | then | ||
| 214 | (); | ||
| 215 | |||
| 216 | //else | ||
| 217 | // algorithm | ||
| 218 | // print(getInstanceName() + " skipping:\n" + | ||
| 219 | // SCodeDump.unparseElementStr(e) + "\n"); | ||
| 220 | // then | ||
| 221 | // (); | ||
| 222 | end match; | ||
| 223 | end for; | ||
| 224 | |||
| 225 | 79604 | tree := PARTIAL_TREE(ltree, clss, comps, exts, listArray(imps), dups); | |
| 226 | end fromSCode; | ||
| 227 | |||
| 228 | function initImports | ||
| 229 | "Initializes imports by resolving unqualified imports and adding all of | ||
| 230 | the imports to the lookup tree. To allow a package to import itself with | ||
| 231 | an unqualified import this needs to be done after the class tree created | ||
| 232 | by fromSCode has been added to the package node." | ||
| 233 | input output ClassTree tree; | ||
| 234 | input InstNode parent; | ||
| 235 | protected | ||
| 236 | array<Import> imports; | ||
| 237 | list<Import> init_imports; | ||
| 238 | Import imp; | ||
| 239 | LookupTree.Tree ltree; | ||
| 240 | algorithm | ||
| 241 | () := match tree | ||
| 242 | case PARTIAL_TREE(tree = ltree, imports = imports) | ||
| 243 | guard not arrayEmpty(imports) | ||
| 244 | algorithm | ||
| 245 | init_imports := {}; | ||
| 246 | |||
| 247 | // Instantiate unqualified imports, since we need to know which names they import. | ||
| 248 | // The names of qualified imports are given by the imports themselves, so we can | ||
| 249 | // delay resolving them until they're used to avoid some dependency issues | ||
| 250 | // (like when a package is imported into one of its enclosing scopes). | ||
| 251 |
2/2✓ Branch 1 taken 12554 times.
✓ Branch 2 taken 7686 times.
|
20240 | for imp in imports loop |
| 252 | init_imports := match imp | ||
| 253 | case Import.UNRESOLVED_IMPORT(imp = Absyn.Import.UNQUAL_IMPORT()) | ||
| 254 | 15 | then Import.instUnqualified(imp, init_imports); | |
| 255 | else imp :: init_imports; | ||
| 256 | end match; | ||
| 257 | end for; | ||
| 258 | |||
| 259 | 7686 | imports := listArray(init_imports); | |
| 260 |
1/2✓ Branch 0 taken 7686 times.
✗ Branch 1 not taken.
|
21877 | for i in arrayLength(imports):-1:1 loop |
| 261 | 14191 | ltree := addImport(imports[i], i, ltree, imports); | |
| 262 | end for; | ||
| 263 | |||
| 264 | 7686 | tree.imports := imports; | |
| 265 | 7686 | tree.tree := ltree; | |
| 266 | then | ||
| 267 | (); | ||
| 268 | |||
| 269 | else (); | ||
| 270 | end match; | ||
| 271 | end initImports; | ||
| 272 | |||
| 273 | function fromEnumeration | ||
| 274 | "Creates a class tree for an enumeration type." | ||
| 275 | input list<SCode.Enum> literals "The SCode literals"; | ||
| 276 | input Type enumType "The type of the enumeration"; | ||
| 277 | input InstNode enumClass "The InstNode of the enumeration type"; | ||
| 278 | output ClassTree tree; | ||
| 279 | protected | ||
| 280 | array<InstNode> comps; | ||
| 281 | Integer attr_count = 5; | ||
| 282 | Integer i = 0; | ||
| 283 | InstNode comp; | ||
| 284 | LookupTree.Tree ltree; | ||
| 285 | String name; | ||
| 286 | algorithm | ||
| 287 | 1179 | comps := arrayCreateNoInit(listLength(literals) + attr_count, InstNode.EMPTY_NODE()); | |
| 288 | ltree := NFBuiltin.ENUM_LOOKUP_TREE; | ||
| 289 | |||
| 290 | 1179 | arrayUpdateNoBoundsChecking(comps, 1, InstNode.fromComponent("quantity", | |
| 291 | Component.TYPE_ATTRIBUTE(Type.STRING(), Modifier.NOMOD()), enumClass)); | ||
| 292 | 1179 | arrayUpdateNoBoundsChecking(comps, 2, InstNode.fromComponent("min", | |
| 293 | Component.TYPE_ATTRIBUTE(enumType, Modifier.NOMOD()), enumClass)); | ||
| 294 | 1179 | arrayUpdateNoBoundsChecking(comps, 3, InstNode.fromComponent("max", | |
| 295 | Component.TYPE_ATTRIBUTE(enumType, Modifier.NOMOD()), enumClass)); | ||
| 296 | 1179 | arrayUpdateNoBoundsChecking(comps, 4, InstNode.fromComponent("start", | |
| 297 | Component.TYPE_ATTRIBUTE(enumType, Modifier.NOMOD()), enumClass)); | ||
| 298 | 1179 | arrayUpdateNoBoundsChecking(comps, 5, InstNode.fromComponent("fixed", | |
| 299 | Component.TYPE_ATTRIBUTE(Type.BOOLEAN(), Modifier.NOMOD()), enumClass)); | ||
| 300 | |||
| 301 |
2/2✓ Branch 0 taken 4468 times.
✓ Branch 1 taken 1178 times.
|
5646 | for l in literals loop |
| 302 | // Make a new component node for the literal and add it to the lookup tree. | ||
| 303 | 4468 | name := l.literal; | |
| 304 | 4468 | i := i + 1; | |
| 305 | 4468 | comp := InstNode.fromComponent(name, Component.newEnum(enumType, name, l.comment, i), enumClass); | |
| 306 | 4468 | arrayUpdateNoBoundsChecking(comps, i + attr_count, comp); | |
| 307 | 4468 | ltree := LookupTree.add(ltree, name, LookupTree.Entry.COMPONENT(i + attr_count), | |
| 308 | function addEnumConflict(literal = comp)); | ||
| 309 | end for; | ||
| 310 | |||
| 311 | // Enumerations can't contain extends, so we can go directly to a flat tree here. | ||
| 312 | 1178 | tree := FLAT_TREE(ltree, listArray({}), comps, listArray({}), DuplicateTree.EMPTY()); | |
| 313 | end fromEnumeration; | ||
| 314 | |||
| 315 | function addElementsToFlatTree | ||
| 316 | "Adds a list of class and/or component nodes as elements to a flat class | ||
| 317 | tree, in the same order as they are listed. Name conflicts will result in | ||
| 318 | an duplicate element error, and trying to add nodes that are not pure | ||
| 319 | class or component nodes will result in undefined behaviour." | ||
| 320 | input list<InstNode> elements; | ||
| 321 | input output ClassTree tree; | ||
| 322 | protected | ||
| 323 | LookupTree.Tree ltree; | ||
| 324 | array<InstNode> cls_arr, comp_arr; | ||
| 325 | list<InstNode> cls_lst = {}, comp_lst = {}; | ||
| 326 | array<Import> imports; | ||
| 327 | DuplicateTree.Tree duplicates; | ||
| 328 | Integer cls_idx, comp_idx; | ||
| 329 | LookupTree.Entry lentry; | ||
| 330 | algorithm | ||
| 331 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
|
12 | FLAT_TREE(ltree, cls_arr, comp_arr, imports, duplicates) := tree; |
| 332 | cls_idx := arrayLength(cls_arr); | ||
| 333 | comp_idx := arrayLength(comp_arr); | ||
| 334 | |||
| 335 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 12 times.
|
74 | for e in elements loop |
| 336 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
62 | if InstNode.isComponent(e) then |
| 337 | 62 | comp_idx := comp_idx + 1; | |
| 338 | 62 | lentry := LookupTree.Entry.COMPONENT(comp_idx); | |
| 339 | comp_lst := e :: comp_lst; | ||
| 340 | else | ||
| 341 | ✗ | cls_idx := cls_idx + 1; | |
| 342 | ✗ | lentry := LookupTree.Entry.CLASS(cls_idx); | |
| 343 | cls_lst := e :: cls_lst; | ||
| 344 | end if; | ||
| 345 | |||
| 346 | 62 | ltree := addLocalElement(InstNode.name(e), lentry, tree, ltree); | |
| 347 | end for; | ||
| 348 | |||
| 349 | 12 | cls_arr := Array.appendList(cls_arr, listReverseInPlace(cls_lst)); | |
| 350 | 12 | comp_arr := Array.appendList(comp_arr, listReverseInPlace(comp_lst)); | |
| 351 | 12 | tree := FLAT_TREE(ltree, cls_arr, comp_arr, imports, duplicates); | |
| 352 | end addElementsToFlatTree; | ||
| 353 | |||
| 354 | function expand | ||
| 355 | "This function adds all local and inherited class and component names to | ||
| 356 | the lookup tree. Note that only their names are added, the elements | ||
| 357 | themselves are added to their respective arrays by the instantiation | ||
| 358 | function below." | ||
| 359 | input output ClassTree tree; | ||
| 360 | protected | ||
| 361 | LookupTree.Tree ltree; | ||
| 362 | LookupTree.Entry lentry; | ||
| 363 | array<InstNode> exts, clss, comps; | ||
| 364 | array<Import> imps; | ||
| 365 | list<tuple<Integer, Integer>> ext_idxs = {}; | ||
| 366 | Integer cls_idx, comp_idx = 1; | ||
| 367 | DuplicateTree.Tree dups; | ||
| 368 | Mutable<DuplicateTree.Tree> dups_ptr; | ||
| 369 | algorithm | ||
| 370 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 71353 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 71353 times.
|
71353 | PARTIAL_TREE(ltree, clss, comps, exts, imps, dups) := tree; |
| 371 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 71353 times.
|
71353 | cls_idx := arrayLength(clss) + 1; |
| 372 | |||
| 373 | // Since we now know the names of both local and inherited components we | ||
| 374 | // can add them to the lookup tree. First we add the local components' | ||
| 375 | // names, to be able to catch duplicate local elements easier. | ||
| 376 |
2/2✓ Branch 1 taken 299301 times.
✓ Branch 2 taken 71323 times.
|
370624 | for c in comps loop |
| 377 | () := match c | ||
| 378 | // A component. Add its name to the lookup tree. | ||
| 379 | case InstNode.COMPONENT_NODE() | ||
| 380 | algorithm | ||
| 381 | 255582 | lentry := LookupTree.Entry.COMPONENT(comp_idx); | |
| 382 | 255582 | ltree := addLocalElement(InstNode.name(c), lentry, tree, ltree); | |
| 383 | |||
| 384 | // If the component is an element redeclare, add an entry in the duplicate | ||
| 385 | // tree so we can check later that it actually redeclares something. | ||
| 386 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 255567 times.
|
255578 | if InstNode.isRedeclare(c) then |
| 387 | 11 | dups := DuplicateTree.add(dups, c.name, DuplicateTree.newRedeclare(lentry)); | |
| 388 | end if; | ||
| 389 | |||
| 390 | 255578 | comp_idx := comp_idx + 1; | |
| 391 | then | ||
| 392 | (); | ||
| 393 | |||
| 394 | // An extends node. Save the index so we know where to start adding | ||
| 395 | // components later, and increment the index with the number of | ||
| 396 | // components it contains. | ||
| 397 | case InstNode.REF_NODE() | ||
| 398 | algorithm | ||
| 399 | 43719 | ext_idxs := (cls_idx - 1, comp_idx - 1) :: ext_idxs; | |
| 400 | 43719 | (cls_idx, comp_idx) := countInheritedElements(exts[c.index], cls_idx, comp_idx); | |
| 401 | then | ||
| 402 | (); | ||
| 403 | |||
| 404 | else | ||
| 405 | algorithm | ||
| 406 | ✗ | Error.terminate(getInstanceName() + " got invalid component", sourceInfo()); | |
| 407 | ✗ | then | |
| 408 | fail(); | ||
| 409 | end match; | ||
| 410 | end for; | ||
| 411 | |||
| 412 | // Checking whether inherited duplicate elements are identical is hard to | ||
| 413 | // do correctly at this point. So we just detect them and store their | ||
| 414 | // indices in the class tree for now, and check them for identicalness | ||
| 415 | // later on instead. | ||
| 416 | 71323 | dups_ptr := Mutable.create(dups); | |
| 417 | |||
| 418 | // Add the names of inherited components and classes to the lookup tree. | ||
| 419 |
2/2✓ Branch 0 taken 42211 times.
✓ Branch 1 taken 29112 times.
|
71323 | if not listEmpty(ext_idxs) then |
| 420 | // Use the component indices we saved earlier to add the required | ||
| 421 | // elements from the extends nodes to the lookup tree. | ||
| 422 | 42211 | ext_idxs := listReverseInPlace(ext_idxs); | |
| 423 | |||
| 424 |
2/2✓ Branch 1 taken 43693 times.
✓ Branch 2 taken 42211 times.
|
85904 | for ext in exts loop |
| 425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43693 times.
|
43693 | (cls_idx, comp_idx) :: ext_idxs := ext_idxs; |
| 426 | 43693 | ltree := expandExtends(ext, ltree, cls_idx, comp_idx, dups_ptr); | |
| 427 | end for; | ||
| 428 | end if; | ||
| 429 | |||
| 430 | 71323 | tree := EXPANDED_TREE(ltree, clss, comps, exts, imps, Mutable.access(dups_ptr)); | |
| 431 | end expand; | ||
| 432 | |||
| 433 | function instantiate | ||
| 434 | "This function instantiates an expanded tree. clsNode is the class to | ||
| 435 | be instantiated, while instance is the instance the clsNode belongs to. | ||
| 436 | instance is usually the component which has the class as its type. In | ||
| 437 | some cases the class itself is the instance, like for the top-level | ||
| 438 | model that's being instantiated or packages used for lookup. Because the | ||
| 439 | actual instance of clsNode will then be the cloned clsNode created by | ||
| 440 | this function it's not possible to send in the correct instance in that | ||
| 441 | case, so setting the instance to an empty node is interpreted by this | ||
| 442 | function to mean that the instance should be set to the cloned clsNode." | ||
| 443 | input output InstNode clsNode; | ||
| 444 | input output InstNode instance = InstNode.EMPTY_NODE(); | ||
| 445 | input InstNode scope = InstNode.EMPTY_NODE(); | ||
| 446 | output Integer classCount = 0; | ||
| 447 | output Integer compCount = 0; | ||
| 448 | protected | ||
| 449 | Class cls; | ||
| 450 | ClassTree tree; | ||
| 451 | LookupTree.Tree ltree; | ||
| 452 | array<InstNode> exts, old_clss, old_comps; | ||
| 453 | array<Import> imps; | ||
| 454 | array<Mutable<InstNode>> clss, comps, ext_clss; | ||
| 455 | list<Integer> local_comps = {}; | ||
| 456 | Integer cls_idx = 1, comp_idx = 1, cls_count, comp_count; | ||
| 457 | InstNode node, parent_scope, inst_scope; | ||
| 458 | NFInstNode.ScopeRef inst_ref; | ||
| 459 | DuplicateTree.Tree dups; | ||
| 460 | SCode.Element ext_def; | ||
| 461 | Boolean is_typish; | ||
| 462 | InstNodeType inst_ty; | ||
| 463 | Mutable<InstNode> mut_node; | ||
| 464 | list<Mutable<InstNode>> outers = {}; | ||
| 465 | algorithm | ||
| 466 | // TODO: If we don't have any extends we could probably generate a flat | ||
| 467 | // tree directly and skip a lot of this. | ||
| 468 | |||
| 469 | // Clone the class node by replacing the class in the node with itself. | ||
| 470 | 2772097 | cls := InstNode.getClass(clsNode); | |
| 471 | 2772097 | clsNode := InstNode.replaceClass(cls, clsNode); | |
| 472 | // The clone is a new node, not an update of the one it was made from, so | ||
| 473 | // it needs an identity of its own before any child points at it. | ||
| 474 | 2772097 | clsNode := InstNode.reidentify(clsNode); | |
| 475 | |||
| 476 | () := match cls | ||
| 477 | case Class.EXPANDED_CLASS(elements = INSTANTIATED_TREE()) | ||
| 478 | then (); | ||
| 479 | |||
| 480 | case Class.EXPANDED_CLASS() | ||
| 481 | algorithm | ||
| 482 | // If the instance is an empty node, use the cloned clsNode as the instance. | ||
| 483 |
2/2✓ Branch 1 taken 177035 times.
✓ Branch 2 taken 120609 times.
|
297644 | if InstNode.isEmpty(instance) then |
| 484 | 177035 | instance := clsNode; | |
| 485 | 177035 | parent_scope := InstNode.instanceParent(clsNode); | |
| 486 | else | ||
| 487 | 120609 | parent_scope := instance; | |
| 488 | inst_scope := scope; | ||
| 489 | end if; | ||
| 490 | |||
| 491 |
2/2✓ Branch 1 taken 167306 times.
✓ Branch 2 taken 130338 times.
|
297644 | inst_scope := if InstNode.isEmpty(scope) then instance else scope; |
| 492 | |||
| 493 | // Fetch the elements from the class tree. | ||
| 494 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 297642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 297642 times.
|
297644 | EXPANDED_TREE(ltree, old_clss, old_comps, exts, imps, dups) := cls.elements; |
| 495 | |||
| 496 | // Count the number of local classes and components we have. | ||
| 497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 297642 times.
|
297642 | classCount := arrayLength(old_clss); |
| 498 | // The component array contains placeholders for extends, so the length of the | ||
| 499 | // extends array needs to be subtracted here to get the number of components. | ||
| 500 | 297642 | compCount := arrayLength(old_comps) - arrayLength(exts); | |
| 501 | |||
| 502 | // Make a new extends array, and recursively instantiate the extends nodes. | ||
| 503 | 297642 | exts := arrayCopy(exts); | |
| 504 |
2/2✓ Branch 0 taken 151661 times.
✓ Branch 1 taken 145981 times.
|
297642 | for i in 1:arrayLength(exts) loop |
| 505 | // Update the parent of the extends to be the new instance. | ||
| 506 | 157262 | node := exts[i]; | |
| 507 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 157262 times.
|
157262 | InstNodeType.BASE_CLASS(definition = ext_def, ty = inst_ty) := InstNode.nodeType(node); |
| 508 | 157262 | node := InstNode.setNodeType( | |
| 509 | InstNodeType.BASE_CLASS(InstNode.identityCell(instance), ext_def, inst_ty), node); | ||
| 510 | // Instantiate the class tree of the extends. | ||
| 511 | 157262 | (node, _, cls_count, comp_count) := instantiate(node, InstNode.EMPTY_NODE(), inst_scope); | |
| 512 | 157259 | exts[i] := node; | |
| 513 | |||
| 514 | // Add the inherited elements to the class/component counts. | ||
| 515 | 157259 | classCount := cls_count + classCount; | |
| 516 | 157259 | compCount := comp_count + compCount; | |
| 517 | end for; | ||
| 518 | |||
| 519 | // Create new arrays that can hold both local and inherited elements. | ||
| 520 | 297639 | comps := arrayCreateNoInit(compCount, /*dummy*/Mutable.create(InstNode.EMPTY_NODE())); | |
| 521 | 297639 | clss := arrayCreateNoInit(classCount, /*dummy*/Mutable.create(InstNode.EMPTY_NODE())); | |
| 522 | |||
| 523 | // Copy the local classes into the new class array, and set the | ||
| 524 | // class we're instantiating to be their parent. | ||
| 525 |
6/6✓ Branch 1 taken 270359 times.
✓ Branch 2 taken 27280 times.
✓ Branch 4 taken 266674 times.
✓ Branch 5 taken 3685 times.
✓ Branch 7 taken 136 times.
✓ Branch 8 taken 266538 times.
|
297639 | is_typish := Restriction.isType(cls.restriction) or |
| 526 | Restriction.isOperatorRecord(cls.restriction) or | ||
| 527 | Restriction.isOperator(cls.restriction); | ||
| 528 | |||
| 529 |
2/2✓ Branch 1 taken 520342 times.
✓ Branch 2 taken 297638 times.
|
817980 | for c in old_clss loop |
| 530 |
2/2✓ Branch 0 taken 38496 times.
✓ Branch 1 taken 481846 times.
|
520342 | if is_typish then |
| 531 | 38496 | c := InstNode.setParent(clsNode, c); | |
| 532 | else | ||
| 533 | 481846 | c := InstNode.clone(c); | |
| 534 | 481846 | c := InstNode.setParent(instance, c); | |
| 535 | end if; | ||
| 536 | |||
| 537 | // If the class is outer, check that it's valid and link it with | ||
| 538 | // the corresponding inner class. | ||
| 539 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 520338 times.
|
520342 | if InstNode.isOuter(c) then |
| 540 | 4 | checkOuterClass(c); | |
| 541 | 3 | c := linkInnerOuter(c, parent_scope); | |
| 542 | end if; | ||
| 543 | |||
| 544 | 520341 | arrayUpdateNoBoundsChecking(clss, cls_idx, Mutable.create(c)); | |
| 545 | 520341 | cls_idx := cls_idx + 1; | |
| 546 | end for; | ||
| 547 | |||
| 548 | // Copy inherited classes into the new class array. Note that inherited | ||
| 549 | // classes are just inserted after the local ones, and not where the | ||
| 550 | // extends say they should go. The order shouldn't matter for classes, | ||
| 551 | // and otherwise we wouldn't be able to reuse the lookup tree. | ||
| 552 |
2/2✓ Branch 1 taken 157259 times.
✓ Branch 2 taken 297638 times.
|
454897 | for ext in exts loop |
| 553 | () := match Class.classTree(InstNode.getClass(ext)) | ||
| 554 | case INSTANTIATED_TREE(classes = ext_clss) | ||
| 555 | algorithm | ||
| 556 | 130335 | cls_count := arrayLength(ext_clss); | |
| 557 | |||
| 558 |
2/2✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 128011 times.
|
130335 | if cls_count > 0 then |
| 559 | 2324 | Array.copyRange(ext_clss, clss, 1, cls_count, cls_idx); | |
| 560 | 2324 | cls_idx := cls_idx + cls_count; | |
| 561 | end if; | ||
| 562 | then | ||
| 563 | (); | ||
| 564 | |||
| 565 | else (); | ||
| 566 | end match; | ||
| 567 | end for; | ||
| 568 | |||
| 569 | // Copy both local and inherited components into the new array. | ||
| 570 | 297638 | inst_ref := InstNode.identityCell(instance); | |
| 571 |
2/2✓ Branch 1 taken 1110235 times.
✓ Branch 2 taken 297638 times.
|
1407873 | for c in old_comps loop |
| 572 | () := match c | ||
| 573 | case InstNode.COMPONENT_NODE() | ||
| 574 | algorithm | ||
| 575 | // Set the component's parent and create a unique instance for it. | ||
| 576 | 952976 | node := InstNode.cloneComponentInScope(c, inst_ref); | |
| 577 | 952976 | mut_node := Mutable.create(node); | |
| 578 | |||
| 579 | // Outer components are saved so they can be linked with their corresponding inner | ||
| 580 | // further down, to avoid generating missing inners for outer components that have | ||
| 581 | // been removed with break. | ||
| 582 |
2/2✓ Branch 1 taken 1793 times.
✓ Branch 2 taken 951183 times.
|
952976 | if InstNode.isOuter(node) then |
| 583 | outers := mut_node :: outers; | ||
| 584 | end if; | ||
| 585 | |||
| 586 | // Add the node to the component array. | ||
| 587 | arrayUpdateNoBoundsChecking(comps, comp_idx, mut_node); | ||
| 588 | local_comps := comp_idx :: local_comps; | ||
| 589 | 952976 | comp_idx := comp_idx + 1; | |
| 590 | then | ||
| 591 | (); | ||
| 592 | |||
| 593 | case InstNode.REF_NODE() | ||
| 594 | algorithm | ||
| 595 | 157259 | comp_idx := instExtendsComps(exts[c.index], comps, comp_idx); | |
| 596 | then | ||
| 597 | (); | ||
| 598 | end match; | ||
| 599 | end for; | ||
| 600 | |||
| 601 | 297638 | breakComponents(instance, comps, ltree, dups); | |
| 602 | 297635 | linkInnerOuterComponents(outers, inst_scope); | |
| 603 | |||
| 604 | // Sanity check. | ||
| 605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 297634 times.
|
297634 | if comp_idx <> compCount + 1 then |
| 606 | ✗ | Error.terminate(getInstanceName() + " miscounted components in " + | |
| 607 | InstNode.name(clsNode), sourceInfo()); | ||
| 608 | end if; | ||
| 609 | |||
| 610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 297634 times.
|
297634 | if cls_idx <> classCount + 1 then |
| 611 | ✗ | Error.terminate(getInstanceName() + " miscounted classes in " + | |
| 612 | InstNode.name(clsNode), sourceInfo()); | ||
| 613 | end if; | ||
| 614 | |||
| 615 | 297634 | local_comps := listReverseInPlace(local_comps); | |
| 616 | |||
| 617 | // Create a new class tree and update the class in the node. | ||
| 618 | 595268 | cls.elements := INSTANTIATED_TREE(ltree, clss, comps, local_comps, exts, imps, dups); | |
| 619 | then | ||
| 620 | (); | ||
| 621 | |||
| 622 | case Class.EXPANDED_DERIVED(baseClass = node) | ||
| 623 | algorithm | ||
| 624 | 945747 | node := InstNode.setNodeType( | |
| 625 | InstNodeType.BASE_CLASS(InstNode.identityCell(clsNode), | ||
| 626 | InstNode.definition(node), InstNode.nodeType(node)), node); | ||
| 627 | 945747 | (node, instance, classCount, compCount) := instantiate(node, instance, scope); | |
| 628 | 945747 | cls.baseClass := node; | |
| 629 | then | ||
| 630 | (); | ||
| 631 | |||
| 632 | case Class.PARTIAL_BUILTIN(elements = tree as FLAT_TREE(components = old_comps)) | ||
| 633 | algorithm | ||
| 634 |
2/2✓ Branch 1 taken 1496665 times.
✓ Branch 2 taken 28034 times.
|
1524699 | instance := if InstNode.isEmpty(instance) then clsNode else instance; |
| 635 | 1524699 | inst_ref := InstNode.identityCell(instance); | |
| 636 | 3049398 | tree.components := Array.map(old_comps, function InstNode.cloneComponentInScope(parent = inst_ref)); | |
| 637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1524699 times.
|
1524699 | cls.elements := tree; |
| 638 | 1524699 | compCount := arrayLength(old_comps); | |
| 639 | |||
| 640 | // Check that there aren't any break modifiers on this instance. | ||
| 641 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1524699 times.
|
1524699 | for bm in getBreakModsInExtend(instance) loop |
| 642 | ✗ | Error.addSourceMessage(Error.NON_BREAKABLE_ELEMENT, {bm.ident}, SCodeUtil.getModifierInfo(bm.mod)); | |
| 643 | ✗ | fail(); | |
| 644 | end for; | ||
| 645 | then | ||
| 646 | (); | ||
| 647 | |||
| 648 | case Class.PARTIAL_BUILTIN() then (); | ||
| 649 | |||
| 650 | case Class.INSTANCED_CLASS() | ||
| 651 | guard InstNode.isBaseClass(clsNode) | ||
| 652 | algorithm | ||
| 653 | ✗ | InstNodeType.BASE_CLASS(definition = ext_def) := InstNode.nodeType(clsNode); | |
| 654 | ✗ | Error.addSourceMessage(Error.EXTENDS_LOOP, | |
| 655 | {SCodeUtil.getElementName(ext_def)}, InstNode.info(clsNode)); | ||
| 656 | ✗ | then | |
| 657 | fail(); | ||
| 658 | |||
| 659 | else | ||
| 660 | algorithm | ||
| 661 | ✗ | Error.terminate(getInstanceName() + " got invalid class", sourceInfo()); | |
| 662 | ✗ | then | |
| 663 | fail(); | ||
| 664 | |||
| 665 | end match; | ||
| 666 | |||
| 667 | 2772087 | InstNode.updateClass(cls, clsNode); | |
| 668 | end instantiate; | ||
| 669 | |||
| 670 | function fromRecordConstructor | ||
| 671 | input list<InstNode> fields; | ||
| 672 | input InstNode out; | ||
| 673 | output ClassTree tree = EMPTY; | ||
| 674 | protected | ||
| 675 | LookupTree.Tree ltree = LookupTree.new(); | ||
| 676 | Integer i = 1; | ||
| 677 | array<InstNode> comps; | ||
| 678 | algorithm | ||
| 679 | 2789 | comps := arrayCreateNoInit(listLength(fields) + 1, InstNode.EMPTY_NODE()); | |
| 680 | |||
| 681 |
2/2✓ Branch 1 taken 24555 times.
✓ Branch 2 taken 2789 times.
|
27344 | for ci in fields loop |
| 682 | 24555 | comps[i] := ci; | |
| 683 | 24555 | ltree := addLocalElement(InstNode.name(ci), LookupTree.Entry.COMPONENT(i), tree, ltree); | |
| 684 | 24555 | i := i + 1; | |
| 685 | end for; | ||
| 686 | |||
| 687 | 2789 | comps[i] := out; | |
| 688 | 2789 | ltree := addLocalElement(InstNode.name(out), LookupTree.Entry.COMPONENT(i), tree, ltree); | |
| 689 | |||
| 690 | 2789 | tree := FLAT_TREE(ltree, listArray({}), comps, listArray({}), DuplicateTree.new()); | |
| 691 | end fromRecordConstructor; | ||
| 692 | |||
| 693 | function clone | ||
| 694 | input ClassTree tree; | ||
| 695 | output ClassTree outTree; | ||
| 696 | algorithm | ||
| 697 | outTree := match tree | ||
| 698 | local | ||
| 699 | array<InstNode> clss; | ||
| 700 | |||
| 701 | case EXPANDED_TREE() | ||
| 702 | algorithm | ||
| 703 | 3975 | clss := arrayCopy(tree.classes); | |
| 704 | 3975 | clss := Array.mapNoCopy(clss, InstNode.clone); | |
| 705 | 3975 | then | |
| 706 | EXPANDED_TREE(tree.tree, clss, tree.components, tree.exts, tree.imports, tree.duplicates); | ||
| 707 | |||
| 708 | else tree; | ||
| 709 | end match; | ||
| 710 | end clone; | ||
| 711 | |||
| 712 | function mapRedeclareChains | ||
| 713 | input ClassTree tree; | ||
| 714 | input FuncT func; | ||
| 715 | |||
| 716 | partial function FuncT | ||
| 717 | input list<Mutable<InstNode>> chain; | ||
| 718 | end FuncT; | ||
| 719 | algorithm | ||
| 720 | () := match tree | ||
| 721 | case INSTANTIATED_TREE() guard not DuplicateTree.isEmpty(tree.duplicates) | ||
| 722 | algorithm | ||
| 723 | 3023 | DuplicateTree.map(tree.duplicates, | |
| 724 | function mapRedeclareChain(func = func, tree = tree)); | ||
| 725 | then | ||
| 726 | (); | ||
| 727 | |||
| 728 | else (); | ||
| 729 | end match; | ||
| 730 | end mapRedeclareChains; | ||
| 731 | |||
| 732 | function replaceDuplicates | ||
| 733 | "This function replaces all duplicate elements with the element that is | ||
| 734 | kept, such that lookup in the extends nodes will find the correct node." | ||
| 735 | input output ClassTree tree; | ||
| 736 | protected | ||
| 737 | DuplicateTree.Tree duplicates; | ||
| 738 | algorithm | ||
| 739 | () := match tree | ||
| 740 | case INSTANTIATED_TREE() guard not DuplicateTree.isEmpty(tree.duplicates) | ||
| 741 | algorithm | ||
| 742 | 3018 | (duplicates, tree) := DuplicateTree.mapFold(tree.duplicates, replaceDuplicates2, tree); | |
| 743 | 3018 | tree.duplicates := duplicates; | |
| 744 | then | ||
| 745 | (); | ||
| 746 | |||
| 747 | else (); | ||
| 748 | end match; | ||
| 749 | end replaceDuplicates; | ||
| 750 | |||
| 751 | function appendComponentsToInstTree | ||
| 752 | "Appens a list of local components to an instantiated class tree." | ||
| 753 | input list<Mutable<InstNode>> components; | ||
| 754 | input output ClassTree tree; | ||
| 755 | algorithm | ||
| 756 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if listEmpty(components) then |
| 757 | ✗ | return; | |
| 758 | else | ||
| 759 | () := match tree | ||
| 760 | local | ||
| 761 | Integer comp_idx; | ||
| 762 | list<Integer> local_comps; | ||
| 763 | |||
| 764 | case INSTANTIATED_TREE() | ||
| 765 | algorithm | ||
| 766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | comp_idx := arrayLength(tree.components); |
| 767 | 9 | tree.components := Array.appendList(tree.components, components); | |
| 768 | 9 | local_comps := tree.localComponents; | |
| 769 | |||
| 770 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
18 | for i in comp_idx+1:comp_idx+listLength(components) loop |
| 771 | local_comps := i :: local_comps; | ||
| 772 | end for; | ||
| 773 | |||
| 774 | 9 | tree.localComponents := local_comps; | |
| 775 | then | ||
| 776 | (); | ||
| 777 | |||
| 778 | else algorithm | ||
| 779 | ✗ | Error.terminate(getInstanceName() + " failed for non-instantiated tree.", sourceInfo()); | |
| 780 | ✗ | then fail(); | |
| 781 | end match; | ||
| 782 | end if; | ||
| 783 | end appendComponentsToInstTree; | ||
| 784 | |||
| 785 | function appendComponentsToFlatTree | ||
| 786 | "Appens a list of local components to a flat class tree." | ||
| 787 | input list<InstNode> components; | ||
| 788 | input output ClassTree tree; | ||
| 789 | algorithm | ||
| 790 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 17 times.
|
24 | if listEmpty(components) then |
| 791 | 7 | return; | |
| 792 | else | ||
| 793 | () := match tree | ||
| 794 | |||
| 795 | case FLAT_TREE() | ||
| 796 | algorithm | ||
| 797 | 17 | tree.components := Array.appendList(tree.components, components); | |
| 798 | then | ||
| 799 | (); | ||
| 800 | |||
| 801 | else algorithm | ||
| 802 | ✗ | Error.terminate(getInstanceName() + " failed for non-flat tree.", sourceInfo()); | |
| 803 | ✗ | then fail(); | |
| 804 | end match; | ||
| 805 | end if; | ||
| 806 | end appendComponentsToFlatTree; | ||
| 807 | |||
| 808 | function flatten | ||
| 809 | "Flattens a class tree by creating new arrays for the classes and | ||
| 810 | components with any duplicates removed and with the elements no longer | ||
| 811 | being mutable references." | ||
| 812 | input output ClassTree tree; | ||
| 813 | algorithm | ||
| 814 | tree := match tree | ||
| 815 | local | ||
| 816 | array<InstNode> clss, comps; | ||
| 817 | array<Integer> comp_offsets; | ||
| 818 | Integer clsc, compc; | ||
| 819 | list<Integer> dup_comp; | ||
| 820 | LookupTree.Tree ltree; | ||
| 821 | |||
| 822 | case INSTANTIATED_TREE() | ||
| 823 | algorithm | ||
| 824 | // Create a list of indices for any duplicates. | ||
| 825 | 272208 | (_, dup_comp) := enumerateDuplicates(tree.duplicates); | |
| 826 | |||
| 827 | // Allocate new arrays for classes and components. | ||
| 828 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 272208 times.
|
272208 | clsc := arrayLength(tree.classes); |
| 829 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 272208 times.
|
544416 | compc := arrayLength(tree.components) - listLength(dup_comp); |
| 830 | 272208 | clss := arrayCreateNoInit(clsc, InstNode.EMPTY_NODE()); | |
| 831 | 272208 | comps := arrayCreateNoInit(compc, InstNode.EMPTY_NODE()); | |
| 832 | |||
| 833 | // Class duplicates can be ignored since classes are only accessed | ||
| 834 | // through name lookup and not index, so there's no need to spend | ||
| 835 | // time on filtering them out. | ||
| 836 | 272208 | flattenElements(tree.classes, clss); | |
| 837 | |||
| 838 | // Component duplicates should be removed though, since we don't | ||
| 839 | // want any duplicates in the flat model. | ||
| 840 |
2/2✓ Branch 0 taken 269365 times.
✓ Branch 1 taken 2843 times.
|
272208 | if listEmpty(dup_comp) then |
| 841 | // No duplicates, just copy to new array. | ||
| 842 | 269365 | flattenElements(tree.components, comps); | |
| 843 | 269365 | ltree := tree.tree; | |
| 844 | else | ||
| 845 | // Duplicates, create an array of offsets and use it to fill the | ||
| 846 | // new array and update the lookup tree. | ||
| 847 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2843 times.
|
5686 | comp_offsets := createFlatOffsets(arrayLength(tree.components), dup_comp); |
| 848 | 2843 | flattenElementsWithOffset(tree.components, comps, comp_offsets); | |
| 849 | 2843 | ltree := flattenLookupTree(tree.tree, comp_offsets); | |
| 850 | end if; | ||
| 851 | 272208 | then | |
| 852 | FLAT_TREE(ltree, clss, comps, tree.imports, tree.duplicates); | ||
| 853 | |||
| 854 | else tree; | ||
| 855 | end match; | ||
| 856 | end flatten; | ||
| 857 | |||
| 858 | function flattenElements | ||
| 859 | "Copies elements from one array to another while removing the Mutable | ||
| 860 | container for each element." | ||
| 861 | input array<Mutable<InstNode>> elements; | ||
| 862 | input array<InstNode> flatElements; | ||
| 863 | algorithm | ||
| 864 |
2/2✓ Branch 0 taken 341150 times.
✓ Branch 1 taken 200423 times.
|
2274582 | for i in 1:arrayLength(elements) loop |
| 865 | 1733009 | arrayUpdateNoBoundsChecking(flatElements, i, | |
| 866 | Mutable.access(arrayGetNoBoundsChecking(elements, i))); | ||
| 867 | end for; | ||
| 868 | end flattenElements; | ||
| 869 | |||
| 870 | function flattenElementsWithOffset | ||
| 871 | input array<Mutable<InstNode>> elements; | ||
| 872 | input array<InstNode> flatElements; | ||
| 873 | input array<Integer> offsets; | ||
| 874 | protected | ||
| 875 | Integer offset; | ||
| 876 | algorithm | ||
| 877 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2843 times.
|
77230 | for i in 1:arrayLength(elements) loop |
| 878 | 74387 | offset := arrayGetNoBoundsChecking(offsets, i); | |
| 879 | |||
| 880 |
2/2✓ Branch 0 taken 43400 times.
✓ Branch 1 taken 30987 times.
|
74387 | if offset >= 0 then |
| 881 | 43400 | arrayUpdateNoBoundsChecking(flatElements, i - offset, | |
| 882 | Mutable.access(arrayGetNoBoundsChecking(elements, i))); | ||
| 883 | end if; | ||
| 884 | end for; | ||
| 885 | end flattenElementsWithOffset; | ||
| 886 | |||
| 887 | function createFlatOffsets | ||
| 888 | "Creates an array of offsets given an element count and a sorted list of | ||
| 889 | duplicate indices. The offsets indicate how many positions each element | ||
| 890 | is shifted when removing the duplicate elements. The duplicates are | ||
| 891 | marked with -1 in the array. For example: | ||
| 892 | createFlatOffsets(7, {2, 4, 5}) => {0, -1, 1, -1, -1, 3, 3} | ||
| 893 | " | ||
| 894 | input Integer elementCount; | ||
| 895 | input list<Integer> duplicates; | ||
| 896 | output array<Integer> offsets; | ||
| 897 | protected | ||
| 898 | Integer offset = 0; | ||
| 899 | Integer dup; | ||
| 900 | list<Integer> rest_dups; | ||
| 901 | algorithm | ||
| 902 | 2843 | offsets := arrayCreateNoInit(elementCount, 0); | |
| 903 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2843 times.
|
2843 | dup :: rest_dups := duplicates; |
| 904 | |||
| 905 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2843 times.
|
77230 | for i in 1:elementCount loop |
| 906 | |||
| 907 |
2/2✓ Branch 0 taken 30987 times.
✓ Branch 1 taken 43400 times.
|
74387 | if i == dup then |
| 908 |
2/2✓ Branch 0 taken 28144 times.
✓ Branch 1 taken 2843 times.
|
30987 | if listEmpty(rest_dups) then |
| 909 | dup := 0; | ||
| 910 | else | ||
| 911 | 28144 | dup :: rest_dups := rest_dups; | |
| 912 | end if; | ||
| 913 | |||
| 914 | 30987 | offset := offset + 1; | |
| 915 | arrayUpdateNoBoundsChecking(offsets, i, -1); | ||
| 916 | else | ||
| 917 | arrayUpdateNoBoundsChecking(offsets, i, offset); | ||
| 918 | end if; | ||
| 919 | end for; | ||
| 920 | end createFlatOffsets; | ||
| 921 | |||
| 922 | function flattenLookupTree | ||
| 923 | "Traverses a lookup tree and shifts the index of each component entry by | ||
| 924 | using the given offset array, such that the lookup tree can be used to | ||
| 925 | look up components when any duplicates have been removed from the | ||
| 926 | component array." | ||
| 927 | input output LookupTree.Tree tree; | ||
| 928 | input array<Integer> offsets; | ||
| 929 | algorithm | ||
| 930 | 2843 | tree := LookupTree.map(tree, function flattenLookupTree2(offsets = offsets)); | |
| 931 | end flattenLookupTree; | ||
| 932 | |||
| 933 | function flattenLookupTree2 | ||
| 934 | input LookupTree.Key key; | ||
| 935 | input LookupTree.Entry entry; | ||
| 936 | input array<Integer> offsets; | ||
| 937 | output LookupTree.Entry outEntry; | ||
| 938 | algorithm | ||
| 939 | outEntry := match entry | ||
| 940 | case LookupTree.Entry.COMPONENT() | ||
| 941 | 43399 | then LookupTree.Entry.COMPONENT(entry.index - arrayGetNoBoundsChecking(offsets, entry.index)); | |
| 942 | |||
| 943 | else entry; | ||
| 944 | end match; | ||
| 945 | end flattenLookupTree2; | ||
| 946 | |||
| 947 | function lookupElement | ||
| 948 | "Returns the class or component with the given name in the class tree." | ||
| 949 | input String name; | ||
| 950 | input ClassTree tree; | ||
| 951 | output InstNode element; | ||
| 952 | output Boolean isImport; | ||
| 953 | protected | ||
| 954 | LookupTree.Entry entry; | ||
| 955 | algorithm | ||
| 956 | 10519147 | entry := LookupTree.get(lookupTree(tree), name); | |
| 957 | 7656771 | (element, isImport) := resolveEntry(entry, tree); | |
| 958 | end lookupElement; | ||
| 959 | |||
| 960 | function lookupElementPtr | ||
| 961 | input String name; | ||
| 962 | input ClassTree tree; | ||
| 963 | output Mutable<InstNode> element; | ||
| 964 | protected | ||
| 965 | LookupTree.Entry entry; | ||
| 966 | algorithm | ||
| 967 | 407336 | entry := LookupTree.get(lookupTree(tree), name); | |
| 968 | 407332 | element := resolveEntryPtr(entry, tree); | |
| 969 | end lookupElementPtr; | ||
| 970 | |||
| 971 | function lookupElementsPtr | ||
| 972 | input String name; | ||
| 973 | input ClassTree tree; | ||
| 974 | output list<Mutable<InstNode>> elements; | ||
| 975 | protected | ||
| 976 | DuplicateTree.Entry dup_entry; | ||
| 977 | algorithm | ||
| 978 | try | ||
| 979 | 435562 | dup_entry := DuplicateTree.get(getDuplicates(tree), name); | |
| 980 | 28226 | elements := resolveDuplicateEntriesPtr(dup_entry, tree); | |
| 981 | else | ||
| 982 | 407336 | elements := {lookupElementPtr(name, tree)}; | |
| 983 | end try; | ||
| 984 | end lookupElementsPtr; | ||
| 985 | |||
| 986 | function lookupComponentIndex | ||
| 987 | input String name; | ||
| 988 | input ClassTree tree; | ||
| 989 | output Integer index; | ||
| 990 | algorithm | ||
| 991 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 175842 times.
|
175854 | LookupTree.Entry.COMPONENT(index = index) := |
| 992 | LookupTree.get(lookupTree(tree), name); | ||
| 993 | end lookupComponentIndex; | ||
| 994 | |||
| 995 | function nthComponent | ||
| 996 | input Integer index; | ||
| 997 | input ClassTree tree; | ||
| 998 | output InstNode component; | ||
| 999 | algorithm | ||
| 1000 | component := match tree | ||
| 1001 | ✗ | case PARTIAL_TREE() then arrayGet(tree.components, index); | |
| 1002 | ✗ | case EXPANDED_TREE() then arrayGet(tree.components, index); | |
| 1003 | ✗ | case INSTANTIATED_TREE() then Mutable.access(arrayGet(tree.components, index)); | |
| 1004 | 3584 | case FLAT_TREE() then arrayGet(tree.components, index); | |
| 1005 | end match; | ||
| 1006 | end nthComponent; | ||
| 1007 | |||
| 1008 | function mapClasses | ||
| 1009 | input ClassTree tree; | ||
| 1010 | input FuncT func; | ||
| 1011 | |||
| 1012 | partial function FuncT | ||
| 1013 | input output InstNode extendsNode; | ||
| 1014 | end FuncT; | ||
| 1015 | protected | ||
| 1016 | array<InstNode> clss = getClasses(tree); | ||
| 1017 | algorithm | ||
| 1018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7488 times.
|
556722 | for i in 1:arrayLength(clss) loop |
| 1019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 549234 times.
|
549234 | arrayUpdateNoBoundsChecking(clss, i, |
| 1020 | func(arrayGetNoBoundsChecking(clss, i))); | ||
| 1021 | end for; | ||
| 1022 | end mapClasses; | ||
| 1023 | |||
| 1024 | function foldClasses<ArgT> | ||
| 1025 | input ClassTree tree; | ||
| 1026 | input FuncT func; | ||
| 1027 | input output ArgT arg; | ||
| 1028 | |||
| 1029 | partial function FuncT | ||
| 1030 | input InstNode clsNode; | ||
| 1031 | input output ArgT arg; | ||
| 1032 | end FuncT; | ||
| 1033 | protected | ||
| 1034 | array<InstNode> clss = getClasses(tree); | ||
| 1035 | algorithm | ||
| 1036 | ✗ | for cls in clss loop | |
| 1037 | ✗ | arg := func(cls, arg); | |
| 1038 | end for; | ||
| 1039 | end foldClasses; | ||
| 1040 | |||
| 1041 | function applyExtends | ||
| 1042 | input ClassTree tree; | ||
| 1043 | input FuncT func; | ||
| 1044 | partial function FuncT | ||
| 1045 | input InstNode extendsNode; | ||
| 1046 | end FuncT; | ||
| 1047 | protected | ||
| 1048 | array<InstNode> exts = getExtends(tree); | ||
| 1049 | algorithm | ||
| 1050 | ✗ | for ext in exts loop | |
| 1051 | ✗ | func(ext); | |
| 1052 | end for; | ||
| 1053 | end applyExtends; | ||
| 1054 | |||
| 1055 | function mapExtends | ||
| 1056 | "Applies a function to each extends node in the class tree, and updates | ||
| 1057 | the extends array with the returned nodes." | ||
| 1058 | input ClassTree tree; | ||
| 1059 | input FuncT func; | ||
| 1060 | |||
| 1061 | partial function FuncT | ||
| 1062 | input output InstNode extendsNode; | ||
| 1063 | end FuncT; | ||
| 1064 | protected | ||
| 1065 | array<InstNode> exts = getExtends(tree); | ||
| 1066 | algorithm | ||
| 1067 |
2/2✓ Branch 0 taken 437908 times.
✓ Branch 1 taken 454951 times.
|
1364602 | for i in 1:arrayLength(exts) loop |
| 1068 |
1/2✓ Branch 0 taken 471753 times.
✗ Branch 1 not taken.
|
471753 | arrayUpdateNoBoundsChecking(exts, i, |
| 1069 | func(arrayGetNoBoundsChecking(exts, i))); | ||
| 1070 | end for; | ||
| 1071 | end mapExtends; | ||
| 1072 | |||
| 1073 | function foldExtends<ArgT> | ||
| 1074 | input ClassTree tree; | ||
| 1075 | input FuncT func; | ||
| 1076 | input output ArgT arg; | ||
| 1077 | |||
| 1078 | partial function FuncT | ||
| 1079 | input InstNode extendsNode; | ||
| 1080 | input output ArgT arg; | ||
| 1081 | end FuncT; | ||
| 1082 | protected | ||
| 1083 | array<InstNode> exts = getExtends(tree); | ||
| 1084 | algorithm | ||
| 1085 | ✗ | for ext in exts loop | |
| 1086 | ✗ | arg := func(ext, arg); | |
| 1087 | end for; | ||
| 1088 | end foldExtends; | ||
| 1089 | |||
| 1090 | function mapFoldExtends<ArgT> | ||
| 1091 | "Applies a mutating function to each extends node in the class tree. | ||
| 1092 | A given argument is also folded and returned." | ||
| 1093 | input ClassTree tree; | ||
| 1094 | input FuncT func; | ||
| 1095 | input output ArgT arg; | ||
| 1096 | |||
| 1097 | partial function FuncT | ||
| 1098 | input output InstNode ext; | ||
| 1099 | input output ArgT arg; | ||
| 1100 | end FuncT; | ||
| 1101 | protected | ||
| 1102 | array<InstNode> exts = getExtends(tree); | ||
| 1103 | InstNode ext; | ||
| 1104 | algorithm | ||
| 1105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42295 times.
|
86057 | for i in 1:arrayLength(exts) loop |
| 1106 |
1/2✓ Branch 0 taken 43778 times.
✗ Branch 1 not taken.
|
43778 | (ext, arg) := func(arrayGetNoBoundsChecking(exts, i), arg); |
| 1107 | arrayUpdateNoBoundsChecking(exts, i, ext); | ||
| 1108 | end for; | ||
| 1109 | end mapFoldExtends; | ||
| 1110 | |||
| 1111 | function applyLocalComponents | ||
| 1112 | input ClassTree tree; | ||
| 1113 | input FuncT func; | ||
| 1114 | |||
| 1115 | partial function FuncT | ||
| 1116 | input InstNode component; | ||
| 1117 | end FuncT; | ||
| 1118 | algorithm | ||
| 1119 | () := match tree | ||
| 1120 | case INSTANTIATED_TREE() | ||
| 1121 | algorithm | ||
| 1122 |
2/2✓ Branch 0 taken 1882852 times.
✓ Branch 1 taken 551523 times.
|
2434375 | for i in tree.localComponents loop |
| 1123 |
1/2✓ Branch 0 taken 1882852 times.
✗ Branch 1 not taken.
|
1882852 | func(Mutable.access(arrayGetNoBoundsChecking(tree.components, i))); |
| 1124 | end for; | ||
| 1125 | then | ||
| 1126 | (); | ||
| 1127 | |||
| 1128 | case PARTIAL_TREE() | ||
| 1129 | algorithm | ||
| 1130 | ✗ | for c in tree.components loop | |
| 1131 | ✗ | func(c); | |
| 1132 | end for; | ||
| 1133 | then | ||
| 1134 | (); | ||
| 1135 | |||
| 1136 | case EXPANDED_TREE() | ||
| 1137 | algorithm | ||
| 1138 | ✗ | for c in tree.components loop | |
| 1139 | ✗ | func(c); | |
| 1140 | end for; | ||
| 1141 | then | ||
| 1142 | (); | ||
| 1143 | end match; | ||
| 1144 | end applyLocalComponents; | ||
| 1145 | |||
| 1146 | function applyComponents | ||
| 1147 | input ClassTree tree; | ||
| 1148 | input FuncT func; | ||
| 1149 | |||
| 1150 | partial function FuncT | ||
| 1151 | input InstNode component; | ||
| 1152 | end FuncT; | ||
| 1153 | algorithm | ||
| 1154 | () := match tree | ||
| 1155 | case PARTIAL_TREE() | ||
| 1156 | algorithm | ||
| 1157 | ✗ | for c in tree.components loop | |
| 1158 | ✗ | func(c); | |
| 1159 | end for; | ||
| 1160 | then | ||
| 1161 | (); | ||
| 1162 | |||
| 1163 | case EXPANDED_TREE() | ||
| 1164 | algorithm | ||
| 1165 | ✗ | for c in tree.components loop | |
| 1166 | ✗ | func(c); | |
| 1167 | end for; | ||
| 1168 | then | ||
| 1169 | (); | ||
| 1170 | |||
| 1171 | case INSTANTIATED_TREE() | ||
| 1172 | algorithm | ||
| 1173 | ✗ | for c in tree.components loop | |
| 1174 | ✗ | func(Mutable.access(c)); | |
| 1175 | end for; | ||
| 1176 | then | ||
| 1177 | (); | ||
| 1178 | |||
| 1179 | case FLAT_TREE() | ||
| 1180 | algorithm | ||
| 1181 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 688394 times.
✓ Branch 3 taken 7139466 times.
✓ Branch 4 taken 688394 times.
|
8516254 | for c in tree.components loop |
| 1182 |
2/2✓ Branch 0 taken 7139408 times.
✓ Branch 1 taken 58 times.
|
7139466 | func(c); |
| 1183 | end for; | ||
| 1184 | then | ||
| 1185 | (); | ||
| 1186 | |||
| 1187 | else (); | ||
| 1188 | end match; | ||
| 1189 | end applyComponents; | ||
| 1190 | |||
| 1191 | function foldComponents<ArgT> | ||
| 1192 | input ClassTree tree; | ||
| 1193 | input FuncT func; | ||
| 1194 | input output ArgT arg; | ||
| 1195 | |||
| 1196 | partial function FuncT | ||
| 1197 | input InstNode component; | ||
| 1198 | input output ArgT arg; | ||
| 1199 | end FuncT; | ||
| 1200 | algorithm | ||
| 1201 | () := match tree | ||
| 1202 | case PARTIAL_TREE() | ||
| 1203 | algorithm | ||
| 1204 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1795 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1795 times.
|
3590 | for c in tree.components loop |
| 1205 | ✗ | arg := func(c, arg); | |
| 1206 | end for; | ||
| 1207 | then | ||
| 1208 | (); | ||
| 1209 | |||
| 1210 | case EXPANDED_TREE() | ||
| 1211 | algorithm | ||
| 1212 | ✗ | for c in tree.components loop | |
| 1213 | ✗ | arg := func(c, arg); | |
| 1214 | end for; | ||
| 1215 | then | ||
| 1216 | (); | ||
| 1217 | |||
| 1218 | case INSTANTIATED_TREE() | ||
| 1219 | algorithm | ||
| 1220 | ✗ | for c in tree.components loop | |
| 1221 | ✗ | arg := func(Mutable.access(c), arg); | |
| 1222 | end for; | ||
| 1223 | then | ||
| 1224 | (); | ||
| 1225 | |||
| 1226 | case FLAT_TREE() | ||
| 1227 | algorithm | ||
| 1228 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 398049 times.
✓ Branch 3 taken 3756618 times.
✓ Branch 4 taken 398049 times.
|
4552716 | for c in tree.components loop |
| 1229 |
2/2✓ Branch 0 taken 3494965 times.
✓ Branch 1 taken 261653 times.
|
3756618 | arg := func(c, arg); |
| 1230 | end for; | ||
| 1231 | then | ||
| 1232 | (); | ||
| 1233 | |||
| 1234 | else (); | ||
| 1235 | end match; | ||
| 1236 | end foldComponents; | ||
| 1237 | |||
| 1238 | function findComponent | ||
| 1239 | "Returns the first component for which the given function returns true." | ||
| 1240 | input ClassTree tree; | ||
| 1241 | input FuncT func; | ||
| 1242 | output Option<InstNode> component = NONE(); | ||
| 1243 | |||
| 1244 | partial function FuncT | ||
| 1245 | input InstNode component; | ||
| 1246 | output Boolean res; | ||
| 1247 | end FuncT; | ||
| 1248 | algorithm | ||
| 1249 | () := match tree | ||
| 1250 | case PARTIAL_TREE() | ||
| 1251 | algorithm | ||
| 1252 | ✗ | for c in tree.components loop | |
| 1253 | ✗ | if func(c) then | |
| 1254 | component := SOME(c); | ||
| 1255 | ✗ | break; | |
| 1256 | end if; | ||
| 1257 | end for; | ||
| 1258 | then | ||
| 1259 | (); | ||
| 1260 | |||
| 1261 | case EXPANDED_TREE() | ||
| 1262 | algorithm | ||
| 1263 | ✗ | for c in tree.components loop | |
| 1264 | ✗ | if func(c) then | |
| 1265 | component := SOME(c); | ||
| 1266 | ✗ | break; | |
| 1267 | end if; | ||
| 1268 | end for; | ||
| 1269 | then | ||
| 1270 | (); | ||
| 1271 | |||
| 1272 | case INSTANTIATED_TREE() | ||
| 1273 | algorithm | ||
| 1274 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 830 times.
✓ Branch 3 taken 830 times.
✗ Branch 4 not taken.
|
1660 | for c in tree.components loop |
| 1275 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 830 times.
✓ Branch 6 taken 830 times.
✗ Branch 7 not taken.
|
830 | if func(Mutable.access(c)) then |
| 1276 | 830 | component := SOME(Mutable.access(c)); | |
| 1277 | 830 | break; | |
| 1278 | end if; | ||
| 1279 | end for; | ||
| 1280 | then | ||
| 1281 | (); | ||
| 1282 | |||
| 1283 | case FLAT_TREE() | ||
| 1284 | algorithm | ||
| 1285 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✓ Branch 3 taken 554 times.
✓ Branch 4 taken 20 times.
|
600 | for c in tree.components loop |
| 1286 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 554 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 548 times.
|
554 | if func(c) then |
| 1287 | component := SOME(c); | ||
| 1288 | 6 | break; | |
| 1289 | end if; | ||
| 1290 | end for; | ||
| 1291 | then | ||
| 1292 | (); | ||
| 1293 | |||
| 1294 | else (); | ||
| 1295 | end match; | ||
| 1296 | end findComponent; | ||
| 1297 | |||
| 1298 | function classCount | ||
| 1299 | input ClassTree tree; | ||
| 1300 | output Integer count; | ||
| 1301 | algorithm | ||
| 1302 | count := match tree | ||
| 1303 | ✗ | case PARTIAL_TREE() then arrayLength(tree.classes); | |
| 1304 | ✗ | case EXPANDED_TREE() then arrayLength(tree.classes); | |
| 1305 | ✗ | case INSTANTIATED_TREE() then arrayLength(tree.classes); | |
| 1306 | ✗ | case FLAT_TREE() then arrayLength(tree.classes); | |
| 1307 | else 0; | ||
| 1308 | end match; | ||
| 1309 | end classCount; | ||
| 1310 | |||
| 1311 | function componentCount | ||
| 1312 | input ClassTree tree; | ||
| 1313 | output Integer count; | ||
| 1314 | algorithm | ||
| 1315 | count := match tree | ||
| 1316 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 438 times.
|
1314 | case PARTIAL_TREE() then arrayLength(tree.components) - arrayLength(tree.exts); |
| 1317 | ✗ | case EXPANDED_TREE() then arrayLength(tree.components) - arrayLength(tree.exts); | |
| 1318 | ✗ | case INSTANTIATED_TREE() then arrayLength(tree.components); | |
| 1319 | ✗ | case FLAT_TREE() then arrayLength(tree.components); | |
| 1320 | else 0; | ||
| 1321 | end match; | ||
| 1322 | end componentCount; | ||
| 1323 | |||
| 1324 | function extendsCount | ||
| 1325 | input ClassTree tree; | ||
| 1326 | output Integer count = arrayLength(getExtends(tree)); | ||
| 1327 | end extendsCount; | ||
| 1328 | |||
| 1329 | function recursiveElementCount | ||
| 1330 | input ClassTree tree; | ||
| 1331 | output Integer count; | ||
| 1332 | algorithm | ||
| 1333 | ✗ | count := classCount(tree) + componentCount(tree); | |
| 1334 | |||
| 1335 | ✗ | for ext in getExtends(tree) loop | |
| 1336 | ✗ | count := count + ClassTree.recursiveElementCount(Class.classTree(InstNode.getClass(ext))); | |
| 1337 | end for; | ||
| 1338 | end recursiveElementCount; | ||
| 1339 | |||
| 1340 | function checkDuplicates | ||
| 1341 | input ClassTree tree; | ||
| 1342 | algorithm | ||
| 1343 | () := match tree | ||
| 1344 | case INSTANTIATED_TREE() guard not DuplicateTree.isEmpty(tree.duplicates) | ||
| 1345 | algorithm | ||
| 1346 | 3018 | DuplicateTree.fold(tree.duplicates, checkDuplicates2, tree); | |
| 1347 | then | ||
| 1348 | (); | ||
| 1349 | |||
| 1350 | else (); | ||
| 1351 | end match; | ||
| 1352 | end checkDuplicates; | ||
| 1353 | |||
| 1354 | function checkDuplicates2 | ||
| 1355 | input String name; | ||
| 1356 | input DuplicateTree.Entry entry; | ||
| 1357 | input output ClassTree tree; | ||
| 1358 | protected | ||
| 1359 | InstNode kept, dup; | ||
| 1360 | algorithm | ||
| 1361 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 37197 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 37196 times.
|
37197 | if isNone(entry.node) then |
| 1362 | 1 | return; | |
| 1363 | end if; | ||
| 1364 | |||
| 1365 | 37196 | SOME(kept) := entry.node; | |
| 1366 | |||
| 1367 | () := match entry.ty | ||
| 1368 | case NFDuplicateTree.EntryType.REDECLARE | ||
| 1369 | algorithm | ||
| 1370 | |||
| 1371 | then | ||
| 1372 | (); | ||
| 1373 | |||
| 1374 | else | ||
| 1375 | algorithm | ||
| 1376 |
2/2✓ Branch 0 taken 33043 times.
✓ Branch 1 taken 32955 times.
|
65998 | for c in entry.children loop |
| 1377 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 33043 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33043 times.
|
33043 | SOME(dup) := c.node; |
| 1378 | |||
| 1379 |
2/2✓ Branch 1 taken 33042 times.
✓ Branch 2 taken 1 time.
|
33043 | if not InstNode.isEmpty(dup) then |
| 1380 | 33042 | InstNode.checkIdentical(kept, dup); | |
| 1381 | end if; | ||
| 1382 | end for; | ||
| 1383 | then | ||
| 1384 | (); | ||
| 1385 | end match; | ||
| 1386 | end checkDuplicates2; | ||
| 1387 | |||
| 1388 | function isIdentical | ||
| 1389 | input ClassTree tree1; | ||
| 1390 | input ClassTree tree2; | ||
| 1391 | output Boolean identical; | ||
| 1392 | algorithm | ||
| 1393 | identical := true; | ||
| 1394 | end isIdentical; | ||
| 1395 | |||
| 1396 | function getRedeclaredNode | ||
| 1397 | input String name; | ||
| 1398 | input ClassTree tree; | ||
| 1399 | output InstNode node; | ||
| 1400 | protected | ||
| 1401 | DuplicateTree.Entry entry; | ||
| 1402 | algorithm | ||
| 1403 | try | ||
| 1404 | ✗ | entry := DuplicateTree.get(getDuplicates(tree), name); | |
| 1405 | ✗ | entry := listHead(entry.children); | |
| 1406 | |||
| 1407 | ✗ | if isSome(entry.node) then | |
| 1408 | ✗ | SOME(node) := entry.node; | |
| 1409 | else | ||
| 1410 | ✗ | node := resolveEntry(entry.entry, tree); | |
| 1411 | end if; | ||
| 1412 | else | ||
| 1413 | ✗ | Error.terminate(getInstanceName() + " failed on " + name, sourceInfo()); | |
| 1414 | end try; | ||
| 1415 | end getRedeclaredNode; | ||
| 1416 | |||
| 1417 | function setClassExtends | ||
| 1418 | input InstNode extNode; | ||
| 1419 | input output ClassTree tree; | ||
| 1420 | algorithm | ||
| 1421 | 3480 | arrayUpdate(getExtends(tree), 1, extNode); | |
| 1422 | end setClassExtends; | ||
| 1423 | |||
| 1424 | function enumerateComponents | ||
| 1425 | input ClassTree tree; | ||
| 1426 | output list<InstNode> components; | ||
| 1427 | protected | ||
| 1428 | LookupTree.Tree ltree; | ||
| 1429 | array<InstNode> comps; | ||
| 1430 | algorithm | ||
| 1431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15250 times.
|
15250 | FLAT_TREE(tree = ltree, components = comps) := tree; |
| 1432 | 15250 | components := LookupTree.fold(ltree, function enumerateComponents2(comps = comps), {}); | |
| 1433 | end enumerateComponents; | ||
| 1434 | |||
| 1435 | function enumerateComponents2 | ||
| 1436 | input String name; | ||
| 1437 | input LookupTree.Entry entry; | ||
| 1438 | input array<InstNode> comps; | ||
| 1439 | input output list<InstNode> components; | ||
| 1440 | algorithm | ||
| 1441 | () := match entry | ||
| 1442 | case LookupTree.Entry.COMPONENT() | ||
| 1443 | algorithm | ||
| 1444 | 41678 | components := comps[entry.index] :: components; | |
| 1445 | then | ||
| 1446 | (); | ||
| 1447 | |||
| 1448 | else (); | ||
| 1449 | end match; | ||
| 1450 | end enumerateComponents2; | ||
| 1451 | |||
| 1452 | function getClasses | ||
| 1453 | input ClassTree tree; | ||
| 1454 | output array<InstNode> clss; | ||
| 1455 | algorithm | ||
| 1456 | clss := match tree | ||
| 1457 | 7488 | case PARTIAL_TREE() then tree.classes; | |
| 1458 | 3791 | case EXPANDED_TREE() then tree.classes; | |
| 1459 | 2 | case FLAT_TREE() then tree.classes; | |
| 1460 | end match; | ||
| 1461 | end getClasses; | ||
| 1462 | |||
| 1463 | function getExtends | ||
| 1464 | input ClassTree tree; | ||
| 1465 | output array<InstNode> exts; | ||
| 1466 | algorithm | ||
| 1467 | exts := match tree | ||
| 1468 | 118014 | case PARTIAL_TREE() then tree.exts; | |
| 1469 | 19782 | case EXPANDED_TREE() then tree.exts; | |
| 1470 | 1223315 | case INSTANTIATED_TREE() then tree.exts; | |
| 1471 | 134 | else listArray({}); | |
| 1472 | end match; | ||
| 1473 | end getExtends; | ||
| 1474 | |||
| 1475 | function getComponents | ||
| 1476 | input ClassTree tree; | ||
| 1477 | output array<InstNode> comps; | ||
| 1478 | algorithm | ||
| 1479 | comps := match tree | ||
| 1480 | ✗ | case PARTIAL_TREE() then tree.components; | |
| 1481 | ✗ | case EXPANDED_TREE() then tree.components; | |
| 1482 | 352865 | case FLAT_TREE() then tree.components; | |
| 1483 | end match; | ||
| 1484 | end getComponents; | ||
| 1485 | |||
| 1486 | function getImports | ||
| 1487 | input ClassTree tree; | ||
| 1488 | output array<Import> imps; | ||
| 1489 | algorithm | ||
| 1490 | imps := match tree | ||
| 1491 | 100 | case PARTIAL_TREE() then tree.imports; | |
| 1492 | ✗ | case EXPANDED_TREE() then tree.imports; | |
| 1493 | ✗ | case INSTANTIATED_TREE() then tree.imports; | |
| 1494 | 139 | case FLAT_TREE() then tree.imports; | |
| 1495 | end match; | ||
| 1496 | end getImports; | ||
| 1497 | |||
| 1498 | function isEmptyTree | ||
| 1499 | input ClassTree tree; | ||
| 1500 | output Boolean isEmpty; | ||
| 1501 | algorithm | ||
| 1502 | isEmpty := match tree | ||
| 1503 | case EMPTY_TREE() then true; | ||
| 1504 | else false; | ||
| 1505 | end match; | ||
| 1506 | end isEmptyTree; | ||
| 1507 | |||
| 1508 | function appendClasses | ||
| 1509 | input list<InstNode> clsNodes; | ||
| 1510 | input output ClassTree tree; | ||
| 1511 | protected | ||
| 1512 | array<InstNode> classes; | ||
| 1513 | LookupTree.Tree ltree; | ||
| 1514 | algorithm | ||
| 1515 | () := match tree | ||
| 1516 | case PARTIAL_TREE() | ||
| 1517 | algorithm | ||
| 1518 | 10 | (ltree, classes) := appendClasses2(clsNodes, tree.tree, tree.classes); | |
| 1519 | 10 | tree.tree := ltree; | |
| 1520 | 10 | tree.classes := classes; | |
| 1521 | then | ||
| 1522 | (); | ||
| 1523 | |||
| 1524 | case EXPANDED_TREE() | ||
| 1525 | algorithm | ||
| 1526 | ✗ | (ltree, classes) := appendClasses2(clsNodes, tree.tree, tree.classes); | |
| 1527 | ✗ | tree.tree := ltree; | |
| 1528 | ✗ | tree.classes := classes; | |
| 1529 | then | ||
| 1530 | (); | ||
| 1531 | |||
| 1532 | case FLAT_TREE() | ||
| 1533 | algorithm | ||
| 1534 | ✗ | (ltree, classes) := appendClasses2(clsNodes, tree.tree, tree.classes); | |
| 1535 | ✗ | tree.tree := ltree; | |
| 1536 | ✗ | tree.classes := classes; | |
| 1537 | then | ||
| 1538 | (); | ||
| 1539 | end match; | ||
| 1540 | end appendClasses; | ||
| 1541 | |||
| 1542 | function appendClasses2 | ||
| 1543 | input list<InstNode> clsNodes; | ||
| 1544 | input output LookupTree.Tree tree; | ||
| 1545 | input output array<InstNode> classes; | ||
| 1546 | protected | ||
| 1547 | Integer index; | ||
| 1548 | algorithm | ||
| 1549 | index := arrayLength(classes); | ||
| 1550 | 10 | classes := Array.appendList(classes, clsNodes); | |
| 1551 | |||
| 1552 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 10 times.
|
37 | for c in clsNodes loop |
| 1553 | 27 | index := index + 1; | |
| 1554 | 27 | tree := LookupTree.add(tree, InstNode.name(c), LookupTree.Entry.CLASS(index)); | |
| 1555 | end for; | ||
| 1556 | end appendClasses2; | ||
| 1557 | |||
| 1558 | function replaceClass | ||
| 1559 | "Replaces the node for a class with another node. Assumes the class | ||
| 1560 | already exists in the tree, and that the tree isn't instantiated." | ||
| 1561 | input InstNode node; | ||
| 1562 | input output ClassTree tree; | ||
| 1563 | protected | ||
| 1564 | Integer index; | ||
| 1565 | algorithm | ||
| 1566 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 3744 times.
|
3744 | LookupTree.Entry.CLASS(index = index) := |
| 1567 | LookupTree.get(lookupTree(tree), InstNode.name(node)); | ||
| 1568 | 3744 | arrayUpdate(getClasses(tree), index, node); | |
| 1569 | end replaceClass; | ||
| 1570 | |||
| 1571 | protected | ||
| 1572 | |||
| 1573 | function instExtendsComps | ||
| 1574 | input InstNode extNode; | ||
| 1575 | input array<Mutable<InstNode>> comps; | ||
| 1576 | input output Integer index "The first free index in comps"; | ||
| 1577 | protected | ||
| 1578 | array<Mutable<InstNode>> ext_comps_ptrs; | ||
| 1579 | array<InstNode> ext_comps; | ||
| 1580 | Integer comp_count; | ||
| 1581 | algorithm | ||
| 1582 | () := match Class.classTree(InstNode.getClass(extNode)) | ||
| 1583 | case INSTANTIATED_TREE(components = ext_comps_ptrs) | ||
| 1584 | algorithm | ||
| 1585 | comp_count := arrayLength(ext_comps_ptrs); | ||
| 1586 | |||
| 1587 |
2/2✓ Branch 0 taken 31843 times.
✓ Branch 1 taken 98492 times.
|
130335 | if comp_count > 0 then |
| 1588 | 31843 | Array.copyRange(ext_comps_ptrs, comps, 1, comp_count, index); | |
| 1589 | 31843 | index := index + comp_count; | |
| 1590 | end if; | ||
| 1591 | then | ||
| 1592 | (); | ||
| 1593 | |||
| 1594 | case FLAT_TREE(components = ext_comps) | ||
| 1595 | algorithm | ||
| 1596 | comp_count := arrayLength(ext_comps); | ||
| 1597 | |||
| 1598 |
1/2✓ Branch 0 taken 26924 times.
✗ Branch 1 not taken.
|
26924 | if comp_count > 0 then |
| 1599 |
1/2✓ Branch 0 taken 26924 times.
✗ Branch 1 not taken.
|
252090 | for i in index:index+comp_count-1 loop |
| 1600 | 225166 | arrayUpdate(comps, i, Mutable.create(ext_comps[i])); | |
| 1601 | end for; | ||
| 1602 | |||
| 1603 | index := index + comp_count; | ||
| 1604 | end if; | ||
| 1605 | then | ||
| 1606 | (); | ||
| 1607 | |||
| 1608 | else (); | ||
| 1609 | end match; | ||
| 1610 | end instExtendsComps; | ||
| 1611 | |||
| 1612 | function getDuplicates | ||
| 1613 | input ClassTree tree; | ||
| 1614 | output DuplicateTree.Tree duplicates; | ||
| 1615 | algorithm | ||
| 1616 | duplicates := match tree | ||
| 1617 | ✗ | case PARTIAL_TREE() then tree.duplicates; | |
| 1618 | ✗ | case EXPANDED_TREE() then tree.duplicates; | |
| 1619 | 435562 | case INSTANTIATED_TREE() then tree.duplicates; | |
| 1620 | ✗ | case FLAT_TREE() then tree.duplicates; | |
| 1621 | end match; | ||
| 1622 | end getDuplicates; | ||
| 1623 | |||
| 1624 | function lookupTree | ||
| 1625 | input ClassTree ctree; | ||
| 1626 | output LookupTree.Tree ltree; | ||
| 1627 | algorithm | ||
| 1628 | ltree := match ctree | ||
| 1629 | 186927 | case PARTIAL_TREE() then ctree.tree; | |
| 1630 | 31986 | case EXPANDED_TREE() then ctree.tree; | |
| 1631 | 1426642 | case INSTANTIATED_TREE() then ctree.tree; | |
| 1632 | 9459652 | case FLAT_TREE() then ctree.tree; | |
| 1633 | end match; | ||
| 1634 | end lookupTree; | ||
| 1635 | |||
| 1636 | function setLookupTree | ||
| 1637 | input LookupTree.Tree ltree; | ||
| 1638 | input output ClassTree ctree; | ||
| 1639 | algorithm | ||
| 1640 | () := match ctree | ||
| 1641 | ✗ | case PARTIAL_TREE() algorithm ctree.tree := ltree; then (); | |
| 1642 | ✗ | case EXPANDED_TREE() algorithm ctree.tree := ltree; then (); | |
| 1643 | ✗ | case INSTANTIATED_TREE() algorithm ctree.tree := ltree; then (); | |
| 1644 | ✗ | case FLAT_TREE() algorithm ctree.tree := ltree; then (); | |
| 1645 | else (); | ||
| 1646 | end match; | ||
| 1647 | end setLookupTree; | ||
| 1648 | |||
| 1649 | function addLocalElement | ||
| 1650 | input String name; | ||
| 1651 | input LookupTree.Entry entry; | ||
| 1652 | input ClassTree classTree; | ||
| 1653 | input output LookupTree.Tree tree; | ||
| 1654 | algorithm | ||
| 1655 | 1269777 | tree := LookupTree.add(tree, name, entry, | |
| 1656 | function addLocalElementConflict(classTree = classTree)); | ||
| 1657 | end addLocalElement; | ||
| 1658 | |||
| 1659 | function addLocalElementConflict | ||
| 1660 | input LookupTree.Entry newEntry; | ||
| 1661 | input LookupTree.Entry oldEntry; | ||
| 1662 | input String name; | ||
| 1663 | input ClassTree classTree; | ||
| 1664 | output LookupTree.Entry entry; | ||
| 1665 | protected | ||
| 1666 | InstNode n1, n2; | ||
| 1667 | algorithm | ||
| 1668 | entry := match oldEntry | ||
| 1669 | // Local elements overwrite imported elements with same name. | ||
| 1670 | case LookupTree.Entry.IMPORT() then newEntry; | ||
| 1671 | // Otherwise we have two local elements with the same name, which is an error. | ||
| 1672 | else | ||
| 1673 | algorithm | ||
| 1674 | 6 | n1 := findLocalConflictElement(newEntry, classTree); | |
| 1675 | 6 | n2 := findLocalConflictElement(oldEntry, classTree); | |
| 1676 | |||
| 1677 | 18 | Error.addMultiSourceMessage(Error.DOUBLE_DECLARATION_OF_ELEMENTS, | |
| 1678 | {name}, {InstNode.info(n2), InstNode.info(n1)}); | ||
| 1679 | 6 | then | |
| 1680 | fail(); | ||
| 1681 | end match; | ||
| 1682 | end addLocalElementConflict; | ||
| 1683 | |||
| 1684 | function findLocalConflictElement | ||
| 1685 | "Helper function to addLocalElementConflict. Looks up an entry in a | ||
| 1686 | partial class tree." | ||
| 1687 | input LookupTree.Entry entry; | ||
| 1688 | input ClassTree classTree; | ||
| 1689 | output InstNode node = InstNode.EMPTY_NODE(); | ||
| 1690 | algorithm | ||
| 1691 | node := match entry | ||
| 1692 | local | ||
| 1693 | array<InstNode> comps, exts; | ||
| 1694 | Integer i; | ||
| 1695 | |||
| 1696 | // For classes we can just use the normal resolveClass function. | ||
| 1697 | 6 | case LookupTree.Entry.CLASS() then resolveClass(entry.index, classTree); | |
| 1698 | |||
| 1699 | // Components are more complicated, since they are given indices based | ||
| 1700 | // on where they will end up once inherited elements have been inserted | ||
| 1701 | // into the component array. We therefore just count components until we | ||
| 1702 | // get to the given index. Not very efficient, but it doesn't really | ||
| 1703 | // matter at this point since we're just going to show an error and fail. | ||
| 1704 | case LookupTree.Entry.COMPONENT() | ||
| 1705 | algorithm | ||
| 1706 | 6 | i := 0; | |
| 1707 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
6 | PARTIAL_TREE(components = comps, exts = exts) := classTree; |
| 1708 | |||
| 1709 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | for c in comps loop |
| 1710 | i := match c | ||
| 1711 | 8 | case InstNode.COMPONENT_NODE() then i + 1; | |
| 1712 | case InstNode.REF_NODE() | ||
| 1713 | algorithm | ||
| 1714 | ✗ | (_, i) := countInheritedElements(exts[c.index], 0, i); | |
| 1715 | ✗ | then | |
| 1716 | i; | ||
| 1717 | end match; | ||
| 1718 | |||
| 1719 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if i == entry.index then |
| 1720 | node := c; | ||
| 1721 | break; | ||
| 1722 | end if; | ||
| 1723 | end for; | ||
| 1724 | |||
| 1725 | // Make extra sure that we actually found the component. | ||
| 1726 | 6 | Error.assertion(i == entry.index, getInstanceName() + " got invalid entry index", sourceInfo()); | |
| 1727 | then | ||
| 1728 | node; | ||
| 1729 | |||
| 1730 | else | ||
| 1731 | algorithm | ||
| 1732 | ✗ | Error.terminate(getInstanceName() + " got invalid entry", sourceInfo()); | |
| 1733 | ✗ | then | |
| 1734 | fail(); | ||
| 1735 | |||
| 1736 | end match; | ||
| 1737 | end findLocalConflictElement; | ||
| 1738 | |||
| 1739 | function addEnumConflict | ||
| 1740 | "Conflict handler for fromEnumeration." | ||
| 1741 | input LookupTree.Entry newEntry; | ||
| 1742 | input LookupTree.Entry oldEntry; | ||
| 1743 | input String name; | ||
| 1744 | input InstNode literal; | ||
| 1745 | output LookupTree.Entry entry; | ||
| 1746 | algorithm | ||
| 1747 | 2 | Error.addSourceMessage(Error.DOUBLE_DECLARATION_OF_ELEMENTS, | |
| 1748 | {InstNode.name(literal)}, InstNode.info(literal)); | ||
| 1749 | 1 | fail(); | |
| 1750 | end addEnumConflict; | ||
| 1751 | |||
| 1752 | function addImport | ||
| 1753 | input Import imp; | ||
| 1754 | input Integer index; | ||
| 1755 | input output LookupTree.Tree tree; | ||
| 1756 | input array<Import> imports; | ||
| 1757 | algorithm | ||
| 1758 | 14191 | tree := LookupTree.add(tree, Import.name(imp), LookupTree.Entry.IMPORT(index), | |
| 1759 | function addImportConflict(imports = imports)); | ||
| 1760 | end addImport; | ||
| 1761 | |||
| 1762 | function addImportConflict | ||
| 1763 | input LookupTree.Entry newEntry; | ||
| 1764 | input LookupTree.Entry oldEntry; | ||
| 1765 | input String name; | ||
| 1766 | input array<Import> imports; | ||
| 1767 | output LookupTree.Entry entry; | ||
| 1768 | algorithm | ||
| 1769 | entry := match (newEntry, oldEntry) | ||
| 1770 | local | ||
| 1771 | Import imp1, imp2; | ||
| 1772 | |||
| 1773 | case (LookupTree.Entry.IMPORT(), LookupTree.Entry.IMPORT()) | ||
| 1774 | algorithm | ||
| 1775 | 8 | imp1 := imports[newEntry.index]; | |
| 1776 | 8 | imp2 := imports[oldEntry.index]; | |
| 1777 | |||
| 1778 | // Check what kind of imports we have. In case of an error we replace the import | ||
| 1779 | // with the error information, and only print the error if the name is looked up. | ||
| 1780 | entry := match (imp1, imp2) | ||
| 1781 | // Two qualified imports of the same name gives an error. | ||
| 1782 | case (Import.UNRESOLVED_IMPORT(), Import.UNRESOLVED_IMPORT()) | ||
| 1783 | algorithm | ||
| 1784 | 2 | arrayUpdate(imports, oldEntry.index, Import.CONFLICTING_IMPORT(imp1, imp2)); | |
| 1785 | then | ||
| 1786 | oldEntry; | ||
| 1787 | |||
| 1788 | // A name imported from several unqualified imports gives an error. | ||
| 1789 | case (Import.RESOLVED_IMPORT(), Import.RESOLVED_IMPORT()) | ||
| 1790 | algorithm | ||
| 1791 | 2 | arrayUpdate(imports, oldEntry.index, Import.CONFLICTING_IMPORT(imp1, imp2)); | |
| 1792 | then | ||
| 1793 | oldEntry; | ||
| 1794 | |||
| 1795 | // Qualified import overwrites an unqualified. | ||
| 1796 | case (Import.UNRESOLVED_IMPORT(), _) then newEntry; | ||
| 1797 | // oldEntry is either qualified or a delayed error, keep it. | ||
| 1798 | else oldEntry; | ||
| 1799 | end match; | ||
| 1800 | then | ||
| 1801 | entry; | ||
| 1802 | |||
| 1803 | // Other elements overwrite an imported name. | ||
| 1804 | else oldEntry; | ||
| 1805 | end match; | ||
| 1806 | end addImportConflict; | ||
| 1807 | |||
| 1808 | function addDuplicate | ||
| 1809 | "Adds an entry to the duplicates tree." | ||
| 1810 | input String name; | ||
| 1811 | input LookupTree.Entry duplicateEntry; | ||
| 1812 | input LookupTree.Entry keptEntry; | ||
| 1813 | input output Mutable<DuplicateTree.Tree> duplicates; | ||
| 1814 | algorithm | ||
| 1815 | ✗ | Mutable.update(duplicates, | |
| 1816 | DuplicateTree.add(Mutable.access(duplicates), name, | ||
| 1817 | DuplicateTree.newDuplicate(keptEntry, duplicateEntry), addDuplicateConflict)); | ||
| 1818 | end addDuplicate; | ||
| 1819 | |||
| 1820 | function addDuplicateConflict | ||
| 1821 | input DuplicateTree.Entry newEntry; | ||
| 1822 | input DuplicateTree.Entry oldEntry; | ||
| 1823 | input String name; | ||
| 1824 | output DuplicateTree.Entry entry; | ||
| 1825 | algorithm | ||
| 1826 | // The previously kept entry should be either kept or dup, since it's the | ||
| 1827 | // one found during lookup. So we can ignore it here. | ||
| 1828 | ✗ | entry := DuplicateTree.ENTRY(newEntry.entry, NONE(), | |
| 1829 | listHead(newEntry.children) :: oldEntry.children, NFDuplicateTree.EntryType.DUPLICATE); | ||
| 1830 | end addDuplicateConflict; | ||
| 1831 | |||
| 1832 | function resolveEntry | ||
| 1833 | "Resolves a lookup tree entry to an inst node." | ||
| 1834 | input LookupTree.Entry entry; | ||
| 1835 | input ClassTree tree; | ||
| 1836 | output InstNode element; | ||
| 1837 | output Boolean isImport; | ||
| 1838 | algorithm | ||
| 1839 | (element, isImport) := match entry | ||
| 1840 | 1558828 | case LookupTree.Entry.CLASS() then (resolveClass(entry.index, tree), false); | |
| 1841 | 5685278 | case LookupTree.Entry.COMPONENT() then (resolveComponent(entry.index, tree), false); | |
| 1842 | 412665 | case LookupTree.Entry.IMPORT() then (resolveImport(entry.index, tree), true); | |
| 1843 | end match; | ||
| 1844 | end resolveEntry; | ||
| 1845 | |||
| 1846 | function resolveEntryPtr | ||
| 1847 | input LookupTree.Entry entry; | ||
| 1848 | input ClassTree tree; | ||
| 1849 | output Mutable<InstNode> element; | ||
| 1850 | protected | ||
| 1851 | array<Mutable<InstNode>> elems; | ||
| 1852 | algorithm | ||
| 1853 | element := match entry | ||
| 1854 | case LookupTree.Entry.CLASS() | ||
| 1855 | algorithm | ||
| 1856 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16188 times.
|
16188 | INSTANTIATED_TREE(classes = elems) := tree; |
| 1857 | 16188 | then | |
| 1858 | arrayGet(elems, entry.index); | ||
| 1859 | |||
| 1860 | case LookupTree.Entry.COMPONENT() | ||
| 1861 | algorithm | ||
| 1862 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 593044 times.
|
593044 | INSTANTIATED_TREE(components = elems) := tree; |
| 1863 | 593044 | then | |
| 1864 | arrayGet(elems, entry.index); | ||
| 1865 | end match; | ||
| 1866 | end resolveEntryPtr; | ||
| 1867 | |||
| 1868 | function resolveDuplicateEntriesPtr | ||
| 1869 | input DuplicateTree.Entry entry; | ||
| 1870 | input ClassTree tree; | ||
| 1871 | input output list<Mutable<InstNode>> elements = {}; | ||
| 1872 | protected | ||
| 1873 | Mutable<InstNode> node_ptr; | ||
| 1874 | algorithm | ||
| 1875 | 56493 | node_ptr := resolveEntryPtr(entry.entry, tree); | |
| 1876 | elements := node_ptr :: elements; | ||
| 1877 | |||
| 1878 |
2/2✓ Branch 0 taken 28267 times.
✓ Branch 1 taken 56493 times.
|
84760 | for child in entry.children loop |
| 1879 | 28267 | elements := resolveDuplicateEntriesPtr(child, tree, elements); | |
| 1880 | end for; | ||
| 1881 | end resolveDuplicateEntriesPtr; | ||
| 1882 | |||
| 1883 | function resolveClass | ||
| 1884 | input Integer index; | ||
| 1885 | input ClassTree tree; | ||
| 1886 | output InstNode element; | ||
| 1887 | algorithm | ||
| 1888 | element := match tree | ||
| 1889 | 139434 | case PARTIAL_TREE() then arrayGet(tree.classes, index); | |
| 1890 | 6096 | case EXPANDED_TREE() then arrayGet(tree.classes, index); | |
| 1891 | 45589 | case INSTANTIATED_TREE() then Mutable.access(arrayGet(tree.classes, index)); | |
| 1892 | 1367715 | case FLAT_TREE() then arrayGet(tree.classes, index); | |
| 1893 | end match; | ||
| 1894 | end resolveClass; | ||
| 1895 | |||
| 1896 | function resolveComponent | ||
| 1897 | input Integer index; | ||
| 1898 | input ClassTree tree; | ||
| 1899 | output InstNode element; | ||
| 1900 | algorithm | ||
| 1901 | element := match tree | ||
| 1902 | 209863 | case INSTANTIATED_TREE() then Mutable.access(arrayGet(tree.components, index)); | |
| 1903 | 5469402 | case FLAT_TREE() then arrayGet(tree.components, index); | |
| 1904 | end match; | ||
| 1905 | end resolveComponent; | ||
| 1906 | |||
| 1907 | function resolveImport | ||
| 1908 | input Integer index; | ||
| 1909 | input ClassTree tree; | ||
| 1910 | output InstNode element; | ||
| 1911 | protected | ||
| 1912 | array<Import> imports; | ||
| 1913 | Import imp; | ||
| 1914 | Boolean changed; | ||
| 1915 | algorithm | ||
| 1916 | imports := match tree | ||
| 1917 | 2909 | case PARTIAL_TREE() then tree.imports; | |
| 1918 | 520 | case EXPANDED_TREE() then tree.imports; | |
| 1919 | 57563 | case INSTANTIATED_TREE() then tree.imports; | |
| 1920 | 351673 | case FLAT_TREE() then tree.imports; | |
| 1921 | end match; | ||
| 1922 | |||
| 1923 | // Imports are resolved on demand, i.e. here. | ||
| 1924 | 412665 | (element, changed, imp) := Import.resolve(imports[index]); | |
| 1925 | |||
| 1926 | // Save the import if it wasn't already resolved. | ||
| 1927 |
2/2✓ Branch 0 taken 401693 times.
✓ Branch 1 taken 10971 times.
|
412664 | if changed then |
| 1928 | 10971 | arrayUpdate(imports, index, imp); | |
| 1929 | end if; | ||
| 1930 | end resolveImport; | ||
| 1931 | |||
| 1932 | function countElements | ||
| 1933 | "Counts the number of classes, components and extends clauses in a list of | ||
| 1934 | SCode elements." | ||
| 1935 | input list<SCode.Element> elements; | ||
| 1936 | output Integer classCount = 0; | ||
| 1937 | output Integer compCount = 0; | ||
| 1938 | output Integer extCount = 0; | ||
| 1939 | algorithm | ||
| 1940 |
6/6✓ Branch 0 taken 986789 times.
✓ Branch 1 taken 264178 times.
✓ Branch 2 taken 44932 times.
✓ Branch 3 taken 12554 times.
✓ Branch 4 taken 1308453 times.
✓ Branch 5 taken 79606 times.
|
1388059 | for e in elements loop |
| 1941 | () := match e | ||
| 1942 | case SCode.CLASS() | ||
| 1943 | algorithm | ||
| 1944 | 986789 | classCount := classCount + 1; | |
| 1945 | then | ||
| 1946 | (); | ||
| 1947 | |||
| 1948 | case SCode.COMPONENT() | ||
| 1949 | algorithm | ||
| 1950 | 264178 | compCount := compCount + 1; | |
| 1951 | then | ||
| 1952 | (); | ||
| 1953 | |||
| 1954 | case SCode.EXTENDS() | ||
| 1955 | algorithm | ||
| 1956 | 44932 | extCount := extCount + 1; | |
| 1957 | then | ||
| 1958 | (); | ||
| 1959 | |||
| 1960 | else (); | ||
| 1961 | end match; | ||
| 1962 | end for; | ||
| 1963 | end countElements; | ||
| 1964 | |||
| 1965 | function countInheritedElements | ||
| 1966 | input InstNode extendsNode; | ||
| 1967 | input output Integer classCount = 0; | ||
| 1968 | input output Integer componentCount = 0; | ||
| 1969 | protected | ||
| 1970 | array<InstNode> clss, comps, exts; | ||
| 1971 | algorithm | ||
| 1972 | () := match Class.classTree(InstNode.getClass(extendsNode)) | ||
| 1973 | case EXPANDED_TREE(classes = clss, components = comps, exts = exts) | ||
| 1974 | algorithm | ||
| 1975 | // The component array contains placeholders for extends, which need to be | ||
| 1976 | // subtracted to get the proper component count. | ||
| 1977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54893 times.
|
54893 | componentCount := componentCount + arrayLength(comps) - arrayLength(exts); |
| 1978 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54893 times.
|
54893 | classCount := classCount + arrayLength(clss); |
| 1979 | |||
| 1980 |
2/2✓ Branch 1 taken 11638 times.
✓ Branch 2 taken 54893 times.
|
66531 | for ext in exts loop |
| 1981 | 11638 | (classCount, componentCount) := countInheritedElements(ext, classCount, componentCount); | |
| 1982 | end for; | ||
| 1983 | then | ||
| 1984 | (); | ||
| 1985 | |||
| 1986 | case FLAT_TREE(classes = clss, components = comps) | ||
| 1987 | algorithm | ||
| 1988 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 438 times.
|
438 | componentCount := componentCount + arrayLength(comps); |
| 1989 | 438 | classCount := classCount + arrayLength(clss); | |
| 1990 | then | ||
| 1991 | (); | ||
| 1992 | |||
| 1993 | else (); | ||
| 1994 | end match; | ||
| 1995 | end countInheritedElements; | ||
| 1996 | |||
| 1997 | function expandExtends | ||
| 1998 | input InstNode extendsNode "The extends node"; | ||
| 1999 | input output LookupTree.Tree tree "The lookup tree to add names to"; | ||
| 2000 | input Integer classOffset "The index of the first class"; | ||
| 2001 | input Integer componentOffset "The index of the first component"; | ||
| 2002 | input Mutable<DuplicateTree.Tree> duplicates "Duplicate elements info."; | ||
| 2003 | protected | ||
| 2004 | ClassTree cls_tree; | ||
| 2005 | LookupTree.Tree ext_tree; | ||
| 2006 | DuplicateTree.Tree ext_dups, dups; | ||
| 2007 | LookupTree.ConflictFunc conf_func; | ||
| 2008 | algorithm | ||
| 2009 | // The extends node's lookup tree should at this point contain all the | ||
| 2010 | // entries we need, so we don't need to recursively traverse its | ||
| 2011 | // elements. Instead we can just take each entry in the extends node's | ||
| 2012 | // lookup tree, add the class or component index as an offset, and then | ||
| 2013 | // add the entry to the given lookup tree. | ||
| 2014 | 43693 | cls_tree := Class.classTree(InstNode.getClass(extendsNode)); | |
| 2015 | |||
| 2016 | (ext_tree, ext_dups) := match cls_tree | ||
| 2017 | 43257 | case EXPANDED_TREE() then (cls_tree.tree, cls_tree.duplicates); | |
| 2018 | 436 | case FLAT_TREE() then (cls_tree.tree, cls_tree.duplicates); | |
| 2019 | ✗ | else algorithm return; then (tree, DuplicateTree.new()); | |
| 2020 | end match; | ||
| 2021 | |||
| 2022 | // Copy entries from the extends node's duplicate tree if there are any. | ||
| 2023 |
2/2✓ Branch 1 taken 357 times.
✓ Branch 2 taken 43336 times.
|
43693 | if not DuplicateTree.isEmpty(ext_dups) then |
| 2024 | // Offset the entries so they're correct for the inheriting class tree. | ||
| 2025 | 357 | dups := DuplicateTree.map(ext_dups, | |
| 2026 | function offsetDuplicates(classOffset = classOffset, componentOffset = componentOffset)); | ||
| 2027 | // Join the two duplicate trees together. | ||
| 2028 | 357 | dups := DuplicateTree.join(Mutable.access(duplicates), dups, joinDuplicates); | |
| 2029 | 357 | Mutable.update(duplicates, dups); | |
| 2030 | end if; | ||
| 2031 | |||
| 2032 | 43693 | conf_func := function addInheritedElementConflict( | |
| 2033 | duplicates = duplicates, | ||
| 2034 | extDuplicates = ext_dups); | ||
| 2035 | |||
| 2036 | // Copy entries from the extends node's lookup tree. | ||
| 2037 | 43693 | tree := LookupTree.fold(ext_tree, | |
| 2038 | function addInheritedElement( | ||
| 2039 | classOffset = classOffset, | ||
| 2040 | componentOffset = componentOffset, | ||
| 2041 | conflictFunc = conf_func), | ||
| 2042 | tree); | ||
| 2043 | end expandExtends; | ||
| 2044 | |||
| 2045 | function addInheritedElement | ||
| 2046 | input String name; | ||
| 2047 | input LookupTree.Entry entry; | ||
| 2048 | input Integer classOffset; | ||
| 2049 | input Integer componentOffset; | ||
| 2050 | input LookupTree.ConflictFunc conflictFunc; | ||
| 2051 | input output LookupTree.Tree tree; | ||
| 2052 | algorithm | ||
| 2053 | () := match entry | ||
| 2054 | case LookupTree.Entry.CLASS() | ||
| 2055 | algorithm | ||
| 2056 | 34578 | entry.index := entry.index + classOffset; | |
| 2057 | 34578 | tree := LookupTree.add(tree, name, entry, conflictFunc); | |
| 2058 | then | ||
| 2059 | (); | ||
| 2060 | |||
| 2061 | case LookupTree.Entry.COMPONENT() | ||
| 2062 | algorithm | ||
| 2063 | 62141 | entry.index := entry.index + componentOffset; | |
| 2064 | 62141 | tree := LookupTree.add(tree, name, entry, conflictFunc); | |
| 2065 | then | ||
| 2066 | (); | ||
| 2067 | |||
| 2068 | // Ignore IMPORT, since imports aren't inherited. | ||
| 2069 | else (); | ||
| 2070 | end match; | ||
| 2071 | end addInheritedElement; | ||
| 2072 | |||
| 2073 | function addInheritedElementConflict | ||
| 2074 | "Conflict handler for addInheritedComponent." | ||
| 2075 | input LookupTree.Entry newEntry; | ||
| 2076 | input LookupTree.Entry oldEntry; | ||
| 2077 | input String name; | ||
| 2078 | input Mutable<DuplicateTree.Tree> duplicates; | ||
| 2079 | input DuplicateTree.Tree extDuplicates; | ||
| 2080 | output LookupTree.Entry entry; | ||
| 2081 | protected | ||
| 2082 | DuplicateTree.Tree dups; | ||
| 2083 | Option<DuplicateTree.Entry> opt_dup_entry; | ||
| 2084 | DuplicateTree.Entry dup_entry; | ||
| 2085 | Integer new_id = LookupTree.Entry.index(newEntry); | ||
| 2086 | Integer old_id = LookupTree.Entry.index(oldEntry); | ||
| 2087 | DuplicateTree.EntryType ty; | ||
| 2088 | algorithm | ||
| 2089 | // Overwrite the existing entry if it's an import. This happens when a | ||
| 2090 | // class both imports and inherits the same name. | ||
| 2091 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6171 times.
|
6171 | if LookupTree.Entry.isImport(oldEntry) then |
| 2092 | entry := newEntry; | ||
| 2093 | ✗ | return; | |
| 2094 | end if; | ||
| 2095 | |||
| 2096 | 6171 | dups := Mutable.access(duplicates); | |
| 2097 | 6171 | opt_dup_entry := DuplicateTree.getOpt(dups, name); | |
| 2098 | |||
| 2099 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 6171 times.
✓ Branch 2 taken 2258 times.
✓ Branch 3 taken 3913 times.
|
6171 | if isNone(opt_dup_entry) then |
| 2100 | // If no duplicate entry yet exists, add a new one. | ||
| 2101 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 2214 times.
|
2258 | if new_id < old_id then |
| 2102 | entry := newEntry; | ||
| 2103 | 44 | dup_entry := DuplicateTree.newDuplicate(newEntry, oldEntry); | |
| 2104 | else | ||
| 2105 | entry := oldEntry; | ||
| 2106 | 2214 | dup_entry := DuplicateTree.newDuplicate(oldEntry, newEntry); | |
| 2107 | end if; | ||
| 2108 | |||
| 2109 | 2258 | dups := DuplicateTree.add(dups, name, dup_entry); | |
| 2110 | 2258 | Mutable.update(duplicates, dups); | |
| 2111 | else | ||
| 2112 | 3913 | SOME(dup_entry) := opt_dup_entry; | |
| 2113 | 3913 | ty := dup_entry.ty; | |
| 2114 | |||
| 2115 | // Here it's possible for either the new or the old entry to not exist in the duplicate entry. | ||
| 2116 | // The new might not exist simply because it hasn't been added yet, while the old might not | ||
| 2117 | // exist because it wasn't a duplicate in its own scope. At least one of them must exist though, | ||
| 2118 | // since duplicate entries are added for any name occurring more than once. | ||
| 2119 |
2/2✓ Branch 1 taken 3412 times.
✓ Branch 2 taken 501 times.
|
3913 | if not DuplicateTree.idExistsInEntry(newEntry, dup_entry) then |
| 2120 |
2/2✓ Branch 0 taken 3410 times.
✓ Branch 1 taken 2 times.
|
3412 | if ty == NFDuplicateTree.EntryType.REDECLARE then |
| 2121 | // If the existing entry is for a redeclare, then the position of the element | ||
| 2122 | // doesn't matter and the new entry should be added as a child to the redeclare. | ||
| 2123 | entry := newEntry; | ||
| 2124 | 6820 | dup_entry.children := DuplicateTree.newEntry(newEntry) :: dup_entry.children; | |
| 2125 | else | ||
| 2126 | // Otherwise we need to keep the 'first' element as the parent. | ||
| 2127 | // Note that this only actually works for components, since we don't | ||
| 2128 | // preserve the order for classes. But which class we choose shouldn't | ||
| 2129 | // matter since they should be identical. We might also compare e.g. a | ||
| 2130 | // component to a class here, but that will be caught in checkDuplicates. | ||
| 2131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if new_id < old_id then |
| 2132 | entry := newEntry; | ||
| 2133 | ✗ | dup_entry := DuplicateTree.Entry.ENTRY(newEntry, NONE(), | |
| 2134 | DuplicateTree.newEntry(oldEntry) :: dup_entry.children, dup_entry.ty); | ||
| 2135 | else | ||
| 2136 | entry := oldEntry; | ||
| 2137 | 4 | dup_entry.children := DuplicateTree.newEntry(newEntry) :: dup_entry.children; | |
| 2138 | end if; | ||
| 2139 | end if; | ||
| 2140 | |||
| 2141 | 3412 | dups := DuplicateTree.update(dups, name, dup_entry); | |
| 2142 | 3412 | Mutable.update(duplicates, dups); | |
| 2143 | elseif not DuplicateTree.idExistsInEntry(oldEntry, dup_entry) then | ||
| 2144 | // Same as above but we add the old entry instead. | ||
| 2145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if ty == NFDuplicateTree.EntryType.REDECLARE or new_id < old_id then |
| 2146 | entry := newEntry; | ||
| 2147 | ✗ | dup_entry.children := DuplicateTree.newEntry(oldEntry) :: dup_entry.children; | |
| 2148 | else | ||
| 2149 | entry := newEntry; | ||
| 2150 | 56 | dup_entry := DuplicateTree.Entry.ENTRY(newEntry, NONE(), | |
| 2151 | DuplicateTree.newEntry(oldEntry) :: dup_entry.children, dup_entry.ty); | ||
| 2152 | end if; | ||
| 2153 | |||
| 2154 | 28 | dups := DuplicateTree.update(dups, name, dup_entry); | |
| 2155 | 28 | Mutable.update(duplicates, dups); | |
| 2156 | else | ||
| 2157 | // If both the old and the new entry already exists, which can happen if the | ||
| 2158 | // new entry was added by expandExtents, then we don't need to add anything. | ||
| 2159 |
1/2✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
|
473 | entry := if new_id < old_id then newEntry else oldEntry; |
| 2160 | end if; | ||
| 2161 | end if; | ||
| 2162 | end addInheritedElementConflict; | ||
| 2163 | |||
| 2164 | function offsetDuplicates | ||
| 2165 | "Offsets all values in the given entry so that they become valid for the | ||
| 2166 | inheriting class." | ||
| 2167 | input String name; | ||
| 2168 | input DuplicateTree.Entry entry; | ||
| 2169 | input Integer classOffset; | ||
| 2170 | input Integer componentOffset; | ||
| 2171 | output DuplicateTree.Entry offsetEntry; | ||
| 2172 | protected | ||
| 2173 | LookupTree.Entry parent; | ||
| 2174 | list<DuplicateTree.Entry> children; | ||
| 2175 | algorithm | ||
| 2176 | 14051 | parent := offsetDuplicate(entry.entry, classOffset, componentOffset); | |
| 2177 |
4/4✓ Branch 0 taken 7454 times.
✓ Branch 1 taken 14051 times.
✓ Branch 2 taken 7454 times.
✓ Branch 3 taken 14051 times.
|
21505 | children := list(offsetDuplicates(name, c, classOffset, componentOffset) for c in entry.children); |
| 2178 | 14051 | offsetEntry := DuplicateTree.ENTRY(parent, NONE(), children, entry.ty); | |
| 2179 | end offsetDuplicates; | ||
| 2180 | |||
| 2181 | function offsetDuplicate | ||
| 2182 | input LookupTree.Entry entry; | ||
| 2183 | input Integer classOffset; | ||
| 2184 | input Integer componentOffset; | ||
| 2185 | output LookupTree.Entry offsetEntry; | ||
| 2186 | algorithm | ||
| 2187 | offsetEntry := match entry | ||
| 2188 | case LookupTree.Entry.CLASS() | ||
| 2189 | 13681 | then LookupTree.Entry.CLASS(entry.index + classOffset); | |
| 2190 | case LookupTree.Entry.COMPONENT() | ||
| 2191 | 370 | then LookupTree.Entry.COMPONENT(entry.index + componentOffset); | |
| 2192 | end match; | ||
| 2193 | end offsetDuplicate; | ||
| 2194 | |||
| 2195 | function joinDuplicates | ||
| 2196 | "Joins two duplicate tree entries together." | ||
| 2197 | input DuplicateTree.Entry newEntry; | ||
| 2198 | input DuplicateTree.Entry oldEntry; | ||
| 2199 | input String name; | ||
| 2200 | output DuplicateTree.Entry entry = oldEntry; | ||
| 2201 | algorithm | ||
| 2202 | // Add the new entry as a child of the old entry. | ||
| 2203 | 473 | entry.children := newEntry :: entry.children; | |
| 2204 | end joinDuplicates; | ||
| 2205 | |||
| 2206 | function enumerateDuplicates | ||
| 2207 | "Returns the indices of the duplicate classes and components, | ||
| 2208 | not including the ones that should be kept." | ||
| 2209 | input DuplicateTree.Tree duplicates; | ||
| 2210 | output list<Integer> classes; | ||
| 2211 | output list<Integer> components; | ||
| 2212 | algorithm | ||
| 2213 |
2/2✓ Branch 1 taken 269012 times.
✓ Branch 2 taken 3196 times.
|
272208 | if DuplicateTree.isEmpty(duplicates) then |
| 2214 | classes := {}; | ||
| 2215 | 269012 | components := {}; | |
| 2216 | else | ||
| 2217 | 3196 | (classes, components) := DuplicateTree.fold_2(duplicates, enumerateDuplicates2, {}, {}); | |
| 2218 | 3196 | classes := List.sort(classes, intGt); | |
| 2219 | 3196 | components := List.sort(components, intGt); | |
| 2220 | end if; | ||
| 2221 | end enumerateDuplicates; | ||
| 2222 | |||
| 2223 | function enumerateDuplicates2 | ||
| 2224 | input String name; | ||
| 2225 | input DuplicateTree.Entry entry; | ||
| 2226 | input output list<Integer> classes; | ||
| 2227 | input output list<Integer> components; | ||
| 2228 | algorithm | ||
| 2229 |
2/2✓ Branch 0 taken 40107 times.
✓ Branch 1 taken 40030 times.
|
80137 | for c in entry.children loop |
| 2230 | 40107 | (classes, components) := enumerateDuplicates3(c, classes, components); | |
| 2231 | end for; | ||
| 2232 | end enumerateDuplicates2; | ||
| 2233 | |||
| 2234 | function enumerateDuplicates3 | ||
| 2235 | input DuplicateTree.Entry entry; | ||
| 2236 | input output list<Integer> classes; | ||
| 2237 | input output list<Integer> components; | ||
| 2238 | algorithm | ||
| 2239 | 41455 | (classes, components) := enumerateDuplicates4(entry.entry, classes, components); | |
| 2240 | |||
| 2241 |
2/2✓ Branch 0 taken 1348 times.
✓ Branch 1 taken 41455 times.
|
42803 | for c in entry.children loop |
| 2242 | 1348 | (classes, components) := enumerateDuplicates3(c, classes, components); | |
| 2243 | end for; | ||
| 2244 | end enumerateDuplicates3; | ||
| 2245 | |||
| 2246 | function enumerateDuplicates4 | ||
| 2247 | input LookupTree.Entry entry; | ||
| 2248 | input output list<Integer> classes; | ||
| 2249 | input output list<Integer> components; | ||
| 2250 | algorithm | ||
| 2251 | () := match entry | ||
| 2252 | case LookupTree.Entry.CLASS() | ||
| 2253 | algorithm | ||
| 2254 | //classes := entry.index :: classes; | ||
| 2255 | then | ||
| 2256 | (); | ||
| 2257 | |||
| 2258 | case LookupTree.Entry.COMPONENT() | ||
| 2259 | algorithm | ||
| 2260 | 30987 | components := entry.index :: components; | |
| 2261 | then | ||
| 2262 | (); | ||
| 2263 | end match; | ||
| 2264 | end enumerateDuplicates4; | ||
| 2265 | |||
| 2266 | function mapRedeclareChain | ||
| 2267 | input String name; | ||
| 2268 | input output DuplicateTree.Entry entry; | ||
| 2269 | input FuncT func; | ||
| 2270 | input ClassTree tree; | ||
| 2271 | |||
| 2272 | partial function FuncT | ||
| 2273 | input list<Mutable<InstNode>> chain; | ||
| 2274 | end FuncT; | ||
| 2275 | protected | ||
| 2276 | list<Mutable<InstNode>> chain; | ||
| 2277 | algorithm | ||
| 2278 | 37202 | chain := getRedeclareChain(entry, tree); | |
| 2279 | |||
| 2280 |
2/2✓ Branch 0 taken 32957 times.
✓ Branch 1 taken 4244 times.
|
37201 | if not listEmpty(chain) then |
| 2281 |
1/2✓ Branch 0 taken 4244 times.
✗ Branch 1 not taken.
|
4244 | func(chain); |
| 2282 | end if; | ||
| 2283 | end mapRedeclareChain; | ||
| 2284 | |||
| 2285 | function getRedeclareChain | ||
| 2286 | input DuplicateTree.Entry entry; | ||
| 2287 | input ClassTree tree; | ||
| 2288 | input output list<Mutable<InstNode>> chain = {}; | ||
| 2289 | algorithm | ||
| 2290 | chain := match entry.ty | ||
| 2291 | local | ||
| 2292 | Mutable<InstNode> node_ptr; | ||
| 2293 | InstNode node; | ||
| 2294 | |||
| 2295 | case NFDuplicateTree.EntryType.REDECLARE | ||
| 2296 | algorithm | ||
| 2297 | 4925 | node_ptr := resolveEntryPtr(entry.entry, tree); | |
| 2298 | |||
| 2299 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4924 times.
|
4925 | if listEmpty(entry.children) then |
| 2300 | 1 | node := Mutable.access(node_ptr); | |
| 2301 | |||
| 2302 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1 | if SCodeUtil.isClassExtends(InstNode.definition(node)) then |
| 2303 | ✗ | Error.addSourceMessage(Error.CLASS_EXTENDS_TARGET_NOT_FOUND, | |
| 2304 | {InstNode.name(node)}, InstNode.info(node)); | ||
| 2305 | else | ||
| 2306 | 2 | Error.addSourceMessage(Error.REDECLARE_NONEXISTING_ELEMENT, | |
| 2307 | {InstNode.name(node)}, InstNode.info(node)); | ||
| 2308 | end if; | ||
| 2309 | |||
| 2310 | 1 | fail(); | |
| 2311 | end if; | ||
| 2312 | 4924 | then | |
| 2313 | getRedeclareChain(listHead(entry.children), tree, node_ptr :: chain); | ||
| 2314 | |||
| 2315 | case NFDuplicateTree.EntryType.ENTRY | ||
| 2316 | algorithm | ||
| 2317 | 4244 | node_ptr := resolveEntryPtr(entry.entry, tree); | |
| 2318 | then | ||
| 2319 | node_ptr :: chain; | ||
| 2320 | |||
| 2321 | else chain; | ||
| 2322 | end match; | ||
| 2323 | end getRedeclareChain; | ||
| 2324 | |||
| 2325 | function replaceDuplicates2 | ||
| 2326 | input String name; | ||
| 2327 | input output DuplicateTree.Entry entry; | ||
| 2328 | input output ClassTree tree; | ||
| 2329 | protected | ||
| 2330 | InstNode kept; | ||
| 2331 | Mutable<InstNode> node_ptr; | ||
| 2332 | InstNode node; | ||
| 2333 | list<DuplicateTree.Entry> entries, broken_entries; | ||
| 2334 | algorithm | ||
| 2335 | () := match entry.ty | ||
| 2336 | case NFDuplicateTree.EntryType.REDECLARE | ||
| 2337 | algorithm | ||
| 2338 | 4241 | kept := Mutable.access(resolveEntryPtr(entry.entry, tree)); | |
| 2339 | 4241 | entry := replaceDuplicates3(entry, kept); | |
| 2340 | then | ||
| 2341 | (); | ||
| 2342 | |||
| 2343 | case NFDuplicateTree.EntryType.DUPLICATE | ||
| 2344 | algorithm | ||
| 2345 | entries := {}; | ||
| 2346 | broken_entries := {}; | ||
| 2347 | kept := InstNode.EMPTY_NODE(); | ||
| 2348 | |||
| 2349 | // Flatten the duplicate list and update the entries. | ||
| 2350 |
2/2✓ Branch 1 taken 66000 times.
✓ Branch 2 taken 32956 times.
|
98956 | for e in DuplicateTree.entryToList(entry) loop |
| 2351 | 66000 | node_ptr := resolveEntryPtr(e.entry, tree); | |
| 2352 | 66000 | node := Mutable.access(node_ptr); | |
| 2353 | 66000 | e.node := SOME(node); | |
| 2354 | 66000 | e.children := {}; | |
| 2355 | |||
| 2356 |
2/2✓ Branch 1 taken 65997 times.
✓ Branch 2 taken 3 times.
|
66000 | if not InstNode.isEmpty(node) then |
| 2357 |
2/2✓ Branch 1 taken 32955 times.
✓ Branch 2 taken 33042 times.
|
65997 | if InstNode.isEmpty(kept) then |
| 2358 | kept := node; | ||
| 2359 | end if; | ||
| 2360 | |||
| 2361 | entries := e :: entries; | ||
| 2362 | else | ||
| 2363 | broken_entries := e :: broken_entries; | ||
| 2364 | end if; | ||
| 2365 | end for; | ||
| 2366 | |||
| 2367 | // Replace duplicate nodes with the node to keep. | ||
| 2368 |
2/2✓ Branch 0 taken 65997 times.
✓ Branch 1 taken 32956 times.
|
98953 | for e in entries loop |
| 2369 | 65997 | node_ptr := resolveEntryPtr(e.entry, tree); | |
| 2370 | 65997 | Mutable.update(node_ptr, kept); | |
| 2371 | end for; | ||
| 2372 | |||
| 2373 | // Update the duplicate entry. | ||
| 2374 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 32955 times.
|
32956 | if listEmpty(entries) then |
| 2375 | 1 | entry.node := NONE(); | |
| 2376 | 1 | entry.children := {}; | |
| 2377 | 1 | return; | |
| 2378 | else | ||
| 2379 | 32955 | entries := listReverseInPlace(entries); | |
| 2380 | 32955 | entry := listHead(entries); | |
| 2381 | 32955 | entry.children := listAppend(listRest(entries), broken_entries); | |
| 2382 | end if; | ||
| 2383 | then | ||
| 2384 | (); | ||
| 2385 | |||
| 2386 | else (); | ||
| 2387 | end match; | ||
| 2388 | end replaceDuplicates2; | ||
| 2389 | |||
| 2390 | function replaceDuplicates3 | ||
| 2391 | input output DuplicateTree.Entry entry; | ||
| 2392 | input InstNode node; | ||
| 2393 | algorithm | ||
| 2394 |
4/4✓ Branch 0 taken 4921 times.
✓ Branch 1 taken 9162 times.
✓ Branch 2 taken 4921 times.
✓ Branch 3 taken 9162 times.
|
14083 | entry.node := SOME(node); |
| 2395 | entry.children := list(replaceDuplicates3(c, node) for c in entry.children); | ||
| 2396 | end replaceDuplicates3; | ||
| 2397 | |||
| 2398 | function linkInnerOuterComponents | ||
| 2399 | "Helper function to instantiate that links a list of outer components | ||
| 2400 | with their corresponding inners." | ||
| 2401 | input list<Mutable<InstNode>> outerComps; | ||
| 2402 | input InstNode scope; | ||
| 2403 | protected | ||
| 2404 | InstNode node; | ||
| 2405 | algorithm | ||
| 2406 |
2/2✓ Branch 0 taken 1793 times.
✓ Branch 1 taken 297634 times.
|
299427 | for c in outerComps loop |
| 2407 | 1793 | node := Mutable.access(c); | |
| 2408 | |||
| 2409 |
1/2✓ Branch 1 taken 1793 times.
✗ Branch 2 not taken.
|
1793 | if not InstNode.isEmpty(node) then |
| 2410 | try | ||
| 2411 | 1793 | node := linkInnerOuter(node, scope); | |
| 2412 | 1792 | Mutable.update(c, node); | |
| 2413 | else | ||
| 2414 | // fail if not NF_API | ||
| 2415 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if not Flags.isSet(Flags.NF_API) then |
| 2416 | 1 | fail(); | |
| 2417 | end if; | ||
| 2418 | end try; | ||
| 2419 | end if; | ||
| 2420 | end for; | ||
| 2421 | end linkInnerOuterComponents; | ||
| 2422 | |||
| 2423 | function linkInnerOuter | ||
| 2424 | "Looks up the corresponding inner node for the given outer node, | ||
| 2425 | and returns an INNER_OUTER_NODE containing them both." | ||
| 2426 | input InstNode outerNode; | ||
| 2427 | input InstNode scope; | ||
| 2428 | output InstNode innerOuterNode; | ||
| 2429 | protected | ||
| 2430 | InstNode inner_node; | ||
| 2431 | algorithm | ||
| 2432 | 1796 | inner_node := Lookup.lookupInner(outerNode, scope); | |
| 2433 | |||
| 2434 | // Make sure we found a node of the same kind. | ||
| 2435 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1795 times.
|
1796 | if valueConstructor(outerNode) <> valueConstructor(inner_node) then |
| 2436 | 6 | Error.addMultiSourceMessage(Error.FOUND_WRONG_INNER_ELEMENT, | |
| 2437 | {InstNode.typeName(inner_node), InstNode.name(outerNode), InstNode.typeName(outerNode)}, | ||
| 2438 | {InstNode.info(outerNode), InstNode.info(inner_node)}); | ||
| 2439 | 1 | fail(); | |
| 2440 | end if; | ||
| 2441 | |||
| 2442 | 1795 | innerOuterNode := InstNode.INNER_OUTER_NODE(inner_node, outerNode); | |
| 2443 | end linkInnerOuter; | ||
| 2444 | |||
| 2445 | function checkOuterClass | ||
| 2446 | "Checks that a class used as outer is valid, i.e. is a short class | ||
| 2447 | definition with no modifier." | ||
| 2448 | input InstNode outerCls; | ||
| 2449 | protected | ||
| 2450 | SCode.ClassDef def; | ||
| 2451 | algorithm | ||
| 2452 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if InstNode.isOnlyOuter(outerCls) then |
| 2453 | 4 | def := SCodeUtil.getClassDef(InstNode.definition(outerCls)); | |
| 2454 | |||
| 2455 | () := match def | ||
| 2456 | // Outer short class definition without mod is ok. | ||
| 2457 | case SCode.ClassDef.DERIVED(modifications = SCode.Mod.NOMOD()) then (); | ||
| 2458 | |||
| 2459 | // Outer short class definition with mod is an error. | ||
| 2460 | case SCode.ClassDef.DERIVED() | ||
| 2461 | algorithm | ||
| 2462 | 3 | Error.addSourceMessage(Error.OUTER_ELEMENT_MOD, | |
| 2463 | {SCodeDump.printModStr(def.modifications), InstNode.name(outerCls)}, | ||
| 2464 | InstNode.info(outerCls)); | ||
| 2465 | 1 | then | |
| 2466 | fail(); | ||
| 2467 | |||
| 2468 | // Outer long class definition is an error. | ||
| 2469 | else | ||
| 2470 | algorithm | ||
| 2471 | ✗ | Error.addSourceMessage(Error.OUTER_LONG_CLASS, | |
| 2472 | {InstNode.name(outerCls)}, InstNode.info(outerCls)); | ||
| 2473 | ✗ | then | |
| 2474 | fail(); | ||
| 2475 | |||
| 2476 | end match; | ||
| 2477 | end if; | ||
| 2478 | end checkOuterClass; | ||
| 2479 | |||
| 2480 | function getBreakModsInExtend | ||
| 2481 | "Returns a list of component break modifiers on a base class node, | ||
| 2482 | or an empty list if the node isn't a base class." | ||
| 2483 | input InstNode extendsNode; | ||
| 2484 | output list<SCode.SubMod> breaks; | ||
| 2485 | protected | ||
| 2486 | SCode.Mod mod; | ||
| 2487 | Option<SCode.Element> opt_def; | ||
| 2488 | algorithm | ||
| 2489 | 1822337 | opt_def := InstNode.extendsDefinition(extendsNode); | |
| 2490 | |||
| 2491 | breaks := match opt_def | ||
| 2492 | case SOME(SCode.Element.EXTENDS(modifications = mod as SCode.Mod.MOD())) | ||
| 2493 |
6/6✓ Branch 1 taken 21272 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 21282 times.
✓ Branch 4 taken 3907 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 3907 times.
|
25189 | then list(sm for sm guard SCodeUtil.isBreakComponentSubMod(sm) in mod.subModLst); |
| 2494 | else {}; | ||
| 2495 | end match; | ||
| 2496 | end getBreakModsInExtend; | ||
| 2497 | |||
| 2498 | function breakComponents | ||
| 2499 | "Applies component break modifiers to the components in a base class." | ||
| 2500 | input InstNode node; | ||
| 2501 | input array<Mutable<InstNode>> components; | ||
| 2502 | input LookupTree.Tree tree; | ||
| 2503 | input DuplicateTree.Tree duplicates; | ||
| 2504 | protected | ||
| 2505 | list<SCode.SubMod> break_mods; | ||
| 2506 | Option<DuplicateTree.Entry> opt_dentry; | ||
| 2507 | Option<LookupTree.Entry> opt_lentry; | ||
| 2508 | list<LookupTree.Entry> entries; | ||
| 2509 | Integer index; | ||
| 2510 | SourceInfo info; | ||
| 2511 | algorithm | ||
| 2512 | 297638 | break_mods := getBreakModsInExtend(node); | |
| 2513 | |||
| 2514 |
2/2✓ Branch 0 taken 297629 times.
✓ Branch 1 taken 9 times.
|
297638 | if listEmpty(break_mods) then |
| 2515 | 297629 | return; | |
| 2516 | end if; | ||
| 2517 | |||
| 2518 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
|
16 | for bm in break_mods loop |
| 2519 | 10 | info := SCodeUtil.getModifierInfo(bm.mod); | |
| 2520 | |||
| 2521 | // Try to look up the name in the duplicate tree first, | ||
| 2522 | // and then in the normal lookup tree if that fails. | ||
| 2523 | 10 | opt_dentry := DuplicateTree.getOpt(duplicates, bm.ident); | |
| 2524 | |||
| 2525 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1 time.
|
10 | if isSome(opt_dentry) then |
| 2526 | 1 | entries := DuplicateTree.getLookupEntries(Util.getOption(opt_dentry)); | |
| 2527 | else | ||
| 2528 | 9 | opt_lentry := LookupTree.getOpt(tree, bm.ident); | |
| 2529 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1 time.
|
9 | entries := if isSome(opt_lentry) then {Util.getOption(opt_lentry)} else {}; |
| 2530 | end if; | ||
| 2531 | |||
| 2532 | // Check that the element exists, and that it's not an imported name | ||
| 2533 | // since those aren't considered when applying modifiers. | ||
| 2534 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 8 times.
|
10 | if listEmpty(entries) or List.all(entries, LookupTree.Entry.isImport) then |
| 2535 | 4 | Error.addSourceMessage(Error.MISSING_MODIFIED_ELEMENT, | |
| 2536 | {bm.ident, InstNode.name(node)}, info); | ||
| 2537 | 2 | fail(); | |
| 2538 | end if; | ||
| 2539 | |||
| 2540 | // Go through the entries, which can be multiple if there are duplicate components. | ||
| 2541 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 7 times.
|
16 | for e in entries loop |
| 2542 | // Check that it's a component. | ||
| 2543 | index := match e | ||
| 2544 | 9 | case LookupTree.Entry.COMPONENT() then e.index; | |
| 2545 | else | ||
| 2546 | algorithm | ||
| 2547 | ✗ | Error.addSourceMessage(Error.NON_BREAKABLE_ELEMENT, {bm.ident}, info); | |
| 2548 | ✗ | then | |
| 2549 | fail(); | ||
| 2550 | end match; | ||
| 2551 | |||
| 2552 | // Check that it's a breakable component. | ||
| 2553 | 9 | checkIsBreakable(Mutable.access(components[index]), node, info); | |
| 2554 | // Replace the component with an empty node. | ||
| 2555 | 8 | Mutable.update(components[index], InstNode.EMPTY_NODE()); | |
| 2556 | end for; | ||
| 2557 | end for; | ||
| 2558 | end breakComponents; | ||
| 2559 | |||
| 2560 | function checkIsBreakable | ||
| 2561 | "Checks that a component is breakable, i.e. a model, block, or connector." | ||
| 2562 | input InstNode node; | ||
| 2563 | input InstNode scope; | ||
| 2564 | input SourceInfo info; | ||
| 2565 | protected | ||
| 2566 | Absyn.Path ty_path; | ||
| 2567 | InstNode cls_node; | ||
| 2568 | SCode.Restriction restriction; | ||
| 2569 | algorithm | ||
| 2570 | try | ||
| 2571 | 9 | ty_path := SCodeUtil.getElementTypePath(InstNode.definition(InstNode.resolveOuter(node))); | |
| 2572 | 9 | cls_node := Lookup.lookupName(ty_path, scope, NFInstContext.NO_CONTEXT, false); | |
| 2573 | 9 | restriction := SCodeUtil.getClassRestriction(InstNode.definition(cls_node)); | |
| 2574 | else | ||
| 2575 | restriction := SCode.Restriction.R_CLASS(); | ||
| 2576 | end try; | ||
| 2577 | |||
| 2578 | () := match restriction | ||
| 2579 | case SCode.Restriction.R_MODEL() then (); | ||
| 2580 | case SCode.Restriction.R_BLOCK() then (); | ||
| 2581 | case SCode.Restriction.R_CONNECTOR() then (); | ||
| 2582 | else | ||
| 2583 | algorithm | ||
| 2584 | 3 | Error.addMultiSourceMessage(Error.NON_BREAKABLE_COMPONENT, | |
| 2585 | {InstNode.name(node)}, {info, InstNode.info(node)}); | ||
| 2586 | 1 | then | |
| 2587 | fail(); | ||
| 2588 | end match; | ||
| 2589 | end checkIsBreakable; | ||
| 2590 | end ClassTree; | ||
| 2591 | |||
| 2592 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 2593 | end NFClassTree; | ||
| 2594 |