Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 81.9% 433 / 0 / 529
Functions: -% 0 / 1 / 1
Branches: 59.4% 244 / 0 / 411

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