Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 84.3% 150 / 0 / 178
Functions: -% 0 / 1 / 1
Branches: 50.0% 44 / 0 / 88

OMCompiler/Compiler/FrontEnd/NFEnvExtends.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 NFEnvExtends
37 " file: NFEnvExtends.mo
38 package: NFEnvExtends
39 description: Utility functions for extends in the environment.
40
41
42 This package contains functions for handling extends in the environment.
43 Extends are added to the environment while the environment is built, and we
44 can't do any lookup at that time since we don't have a complete environment.
45
46 There are several important things done by this package:
47
48 QUALIFYING EXTENDS:
49 All base class names in the environment are fully qualified by the qualify
50 function. This is to avoid potential exponential complexity during lookup with
51 regards to the nesting depth of classes. One such case is the pattern used in
52 the MSL, where every class extends from a a class in Modelica.Icons:
53
54 package Modelica
55 package Icons end Icons;
56
57 package A
58 extends Modelica.Icons.foo;
59 package B
60 extends Modelica.Icons.bar;
61 package C
62 ...
63 end C;
64 end B;
65 end A;
66 end Modelica;
67
68 To look a name up in C that references a name in the top scope we need to
69 first look up in C. When the name is not found there we look in B, which
70 extends Modelica.Icons.bar. We then need to look for Modelica in B, and then
71 Modelica in A, which extends Modelica.Icons.foo. We then need to follow that
72 extends, and look for Modelica in A, etc. This means that we need to look up
73 2^n extends to find a relative name in the top scope. By fully qualifying the
74 base class names we avoid these problems.
75
76 To avoid qualifying an extends multiple times we store them in an array which
77 is updated during the qualifying phase. Each extends is given a unique index
78 for this purpose when it's added to the environment by
79 NFSCodeEnv.extendEnvWithExtends, which is used to index the array.
80
81 When errors are found in this phase, such as missing base classes, we want to
82 only report errors for models which are actually used. We therefore delay the
83 error messages until the extends are used. This is done by returning special
84 error paths instead of the fully qualified paths, see checkExtendsPart for
85 details. When e.g. NFSCodeLookup.lookupBaseClassName encounters such a path it
86 uses printExtendsError to print the appropriate error.
87
88 INSERT ELEMENT REDECLARES INTO EXTENDS:
89 The update function goes through all the scopes and insert element redeclares
90 into the appropriate extends with addElementRedeclarationsToEnv from
91 NFSCodeFlattenRedeclare. See the comment in SCodeFlattenRedeclare for more
92 information about this.
93
94 UPDATE CLASS EXTENDS:
95 Class extends are handled by initially adding them to the environment with
96 NFSCodeEnv.extendEnvWithClassExtends. This function add the given class as a
97 normal class to the environment, and sets the class extends information field
98 in the class's environment. This information is later used when the extends
99 are updated with the update function, and updateClassExtends is called.
100 updateClassExtends looks the base class up and makes sure it is replaceable,
101 and adds an extends clause to the extending class and the environment. The
102 base class will be prefixed with $ce so that the lookup knows that it should
103 look among the inherited elements of the scope above when looking for a class
104 extends base class.
105
106 However, since it's possible to redeclare the base class of a class extends
107 it's possible that the base class is replaced with a class that extends from
108 it. If the base class were to be replaced with this class it would mean that
109 the class extends from itself, causing a loop. To avoid this an alias for the
110 base class is added instead, and the base class itself is added with the
111 BASE_CLASS_SUFFIX defined in NFSCodeEnv. The alias can then be safely redeclared
112 while preserving the base class for the class extends to extend from. It's
113 somewhat difficault to only add aliases for classes that are used by class
114 extends though, so an alias is currently added for all replaceable classes in
115 NFSCodeEnv.extendEnvWithClassDef for simplicity's sake. The function
116 NFSCodeLookup.resolveAlias is then used to resolve any alias items to the real
117 items whenever an item is looked up in the environment.
118
119 So a class extends on the form 'class extends X' is thus translated to
120 'class X extends $ce.X$base', and then mostly handled like a normal class
121 since the lookup knows how to handle the base class. Some care is needed in
122 the dependency analysis to make sure that nothing important is removed, see
123 the comment in SCodeDependency.analyseClassExtends.
124 "
125
126 public import Absyn;
127 public import AbsynUtil;
128 public import SCode;
129 public import NFSCodeEnv;
130
131 protected import Debug;
132 protected import Error;
133 protected import Flags;
134 protected import List;
135 protected import NFSCodeCheck;
136 protected import SCodeDump;
137 import SCodeUtil;
138 protected import NFSCodeFlattenRedeclare;
139 protected import NFSCodeLookup;
140 protected import System;
141 protected import Util;
142
143 public type Env = NFSCodeEnv.Env;
144
145 protected type ClassType = NFSCodeEnv.ClassType;
146 protected type Extends = NFSCodeEnv.Extends;
147 protected type Frame = NFSCodeEnv.Frame;
148 protected type FrameType = NFSCodeEnv.FrameType;
149 protected type Import = Absyn.Import;
150 protected type Item = NFSCodeEnv.Item;
151
152 protected type ExtendsTableArray = array<ExtendsWrapper>;
153
154 import NFSCodeEnv.EnvTree;
155
156 public constant String BASECLASS_NOT_FOUND_ERROR = "$1";
157 public constant String BASECLASS_INHERITED_ERROR = "$2";
158 public constant String BASECLASS_REPLACEABLE_ERROR = "$3";
159 public constant String BASECLASS_IS_VAR_ERROR = "$4";
160 public constant String BASECLASS_UNKNOWN_ERROR = "$5";
161
162 protected uniontype ExtendsWrapper
163 record UNQUALIFIED_EXTENDS
164 Extends ext;
165 end UNQUALIFIED_EXTENDS;
166
167 record QUALIFIED_EXTENDS
168 Extends ext;
169 end QUALIFIED_EXTENDS;
170
171 record NO_EXTENDS end NO_EXTENDS;
172 end ExtendsWrapper;
173
174 public function update
175 "While building the environment some extends information is stored that needs
176 to be updated once the environment is complete, since we can't reliably look
177 things up in an incomplete environment. This includes fully qualifying the
178 names of the extended classes, updating the class extends base classes and
179 inserting element redeclares into the proper extends."
180 input Env inEnv;
181 output Env outEnv;
182 protected
183 Env env;
184 algorithm
185 //System.startTimer();
186 1103 env := qualify(inEnv);
187 1103 outEnv := update2(env);
188 //System.stopTimer();
189 //print("Updating extends took " + realString(System.getTimerIntervalTime()) + " seconds.\n");
190 end update;
191
192 public function qualify
193 "Fully qualified all base class names using in extends clauses. This is done
194 to avoid some cases where the lookup might exhibit exponential complexity
195 with regards to the nesting depth of classes. One such case is the pattern
196 used in the MSL, where every class extends from a class in Modelica.Icons:
197
198 package Modelica
199 package Icons end Icons;
200
201 package A
202 extends Modelica.Icons.foo;
203 package B
204 extends Modelica.Icons.bar;
205 package C
206 ...
207 end C;
208 end B;
209 end A;
210
211 To look a name up in C that references a name in the top scope we need to
212 first look in C. When the name is not found there we look in B, which extends
213 Modelica.Icons.bar. We then need to look for Modelica in B, and then Modelica
214 in A, which extends Modelica.Icons.foo. We then need to follow that extends,
215 and look for Modelica in A, etc. This means that we need to look up 2^n
216 extends to find a relative name at the top scope. By fully qualifying the
217 base class names we avoid these problems."
218 input Env inEnv;
219 output Env outEnv;
220 algorithm
221 outEnv := matchcontinue inEnv
222 local
223 Integer ext_count;
224 ExtendsTableArray ext_table;
225
226 case _
227 algorithm
228 1103 ext_count := System.tmpTickIndex(NFSCodeEnv.extendsTickIndex);
229 1103 ext_table := createExtendsTable(ext_count);
230 1103 then
231 qualify2(inEnv, NFSCodeEnv.USERDEFINED(), ext_table);
232
233 else
234 algorithm
235 ✗ true := Flags.isSet(Flags.FAILTRACE);
236 ✗ Debug.traceln("- NFEnvExtends.qualify failed.");
237 ✗ then
238 fail();
239
240 end matchcontinue;
241 end qualify;
242
243 protected function qualify2
244 input Env inEnv;
245 input ClassType inClassType;
246 input ExtendsTableArray inExtendsTable;
247 output Env outEnv;
248 protected
249 Env env;
250 EnvTree.Tree tree;
251 algorithm
252 // Qualify the extends in this scope.
253 1458066 env := qualifyLocalScope(inEnv, inClassType, inExtendsTable);
254
255 // Recurse down the tree.
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1458066 times.
1458066 NFSCodeEnv.FRAME(clsAndVars = tree) :: _ := env;
257 1458066 tree := EnvTree.map(tree,
258 function qualify3(inEnv = env, inExtendsTable = inExtendsTable));
259 1458066 outEnv := NFSCodeEnv.setEnvClsAndVars(tree, env);
260 end qualify2;
261
262 protected function qualify3
263 input String name;
264 input output Item item;
265 input Env inEnv;
266 input ExtendsTableArray inExtendsTable;
267 algorithm
268 item := match item
269 local
270 SCode.Element cls;
271 Frame cls_env;
272 ClassType cls_ty;
273 Env env;
274
275 case NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty)
276 algorithm
277 1456963 env := NFSCodeEnv.enterFrame(cls_env, inEnv);
278
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1456963 times.
1456963 cls_env :: _ := qualify2(env, cls_ty, inExtendsTable);
279 1456963 then
280 NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty);
281
282 else item;
283 end match;
284 end qualify3;
285
286 protected function qualifyLocalScope
287 input Env inEnv;
288 input ClassType inClassType;
289 input ExtendsTableArray inExtendsTable;
290 output Env outEnv;
291 protected
292 list<Extends> exts;
293 list<SCode.Element> re;
294 Option<SCode.Element> cei;
295 algorithm
296 1458066 NFSCodeEnv.EXTENDS_TABLE(exts, re, cei) := NFSCodeEnv.getEnvExtendsTable(inEnv);
297 1458066 exts := qualifyExtendsList(exts, inClassType, inEnv, inExtendsTable);
298 1458066 outEnv := NFSCodeEnv.setEnvExtendsTable(NFSCodeEnv.EXTENDS_TABLE(exts, re, cei), inEnv);
299 end qualifyLocalScope;
300
301 protected function qualifyExtendsList
302 input list<Extends> inExtends;
303 input ClassType inClassType;
304 input Env inEnv;
305 input ExtendsTableArray inExtendsTable;
306 output list<Extends> outExtends;
307 algorithm
308 outExtends := match(inExtends, inClassType)
309 local
310 Extends ext;
311 list<Extends> extl;
312
313 // Skip the first extends in a class extends, since it's added by the
314 // compiler itself and shouldn't be qualified.
315 case (ext :: extl, NFSCodeEnv.CLASS_EXTENDS())
316 algorithm
317 3749 extl := List.map2Reverse(extl, qualifyExtends, inEnv, inExtendsTable);
318 then
319 ext :: extl;
320
321 // Otherwise, qualify all the extends.
322 else
323 algorithm
324 1454317 extl := List.map2Reverse(inExtends, qualifyExtends, inEnv, inExtendsTable);
325 then
326 extl;
327
328 end match;
329 end qualifyExtendsList;
330
331 protected function qualifyExtends
332 input Extends inExtends;
333 input Env inEnv;
334 input ExtendsTableArray inExtendsTable;
335 output Extends outExtends;
336 algorithm
337 outExtends := matchcontinue inExtends
338 local
339 Absyn.Ident id;
340 Extends ext;
341 Absyn.Path bc;
342
343 // Check if the base class is a built in type such as Real, then we don't
344 // need to do anything.
345 case NFSCodeEnv.EXTENDS(baseClass = Absyn.IDENT(name = id))
346 algorithm
347 97981 NFSCodeLookup.lookupBuiltinType(id);
348 then
349 inExtends;
350
351 case _
352 algorithm
353
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 592151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 592151 times.
592151 SOME(ext) := qualifyExtends2(inExtends, inEnv, inExtendsTable);
354 then
355 ext;
356
357 case NFSCodeEnv.EXTENDS(baseClass = bc)
358 algorithm
359 ✗ true := Flags.isSet(Flags.FAILTRACE);
360 ✗ Debug.traceln("- NFEnvExtends.qualifyExtends failed on " +
361 AbsynUtil.pathString(bc) + "\n");
362 ✗ then
363 fail();
364
365 end matchcontinue;
366 end qualifyExtends;
367
368 protected function qualifyExtends2
369 input Extends inExtends;
370 input Env inEnv;
371 input ExtendsTableArray inExtendsTable;
372 output Option<Extends> outExtends;
373 algorithm
374 outExtends := matchcontinue inExtends
375 local
376 Absyn.Path bc;
377 list<NFSCodeEnv.Redeclaration> rl;
378 Integer index;
379 SourceInfo info;
380 Extends ext;
381 Env env;
382
383 case NFSCodeEnv.EXTENDS(index = index)
384 3561751 then lookupQualifiedExtends(index, inExtendsTable);
385
386 case NFSCodeEnv.EXTENDS(bc, rl, index, info)
387 algorithm
388 592472 addUnqualifiedToTable(inExtends, index, inExtendsTable);
389 592472 env := NFSCodeEnv.removeExtendFromLocalScope(bc, inEnv);
390 592472 bc := qualifyExtends3(bc, env, inExtendsTable, true, bc, info, NONE());
391 /*********************************************************************/
392 // TODO: Convert this check to the delayed error system.
393 /*********************************************************************/
394 592472 List.map2_0(rl, NFSCodeCheck.checkRedeclareModifier, bc, inEnv);
395 592472 ext := NFSCodeEnv.EXTENDS(bc, rl, index, info);
396 592472 updateQualifiedInTable(ext, index, inExtendsTable);
397 then
398 SOME(ext);
399
400 end matchcontinue;
401 end qualifyExtends2;
402
403 protected function qualifyExtends3
404 input Absyn.Path inBaseClass;
405 input Env inEnv;
406 input ExtendsTableArray inExtendsTable;
407 input Boolean inIsFirst;
408 input Absyn.Path inFullPath;
409 input SourceInfo inInfo;
410 input Option<Absyn.Path> inErrorPath;
411 output Absyn.Path outBaseClass;
412 algorithm
413 outBaseClass := match(inBaseClass, inErrorPath)
414 local
415 String name;
416 Absyn.Path bc, rest_path;
417 Env env;
418 Option<Absyn.Path> ep, opath;
419
420 case (_, SOME(bc)) then bc;
421
422 case (Absyn.IDENT(name = name), _)
423 algorithm
424 592461 (opath, env, ep) := qualifyExtendsPart(name, inEnv, inExtendsTable, inIsFirst,
425 inFullPath, inInfo);
426 592461 then
427 makeExtendsPath(opath, NONE(), env, ep, inIsFirst);
428
429 case (Absyn.QUALIFIED(name = name, path = rest_path), _)
430 algorithm
431 1276072 (opath, env, ep) := qualifyExtendsPart(name, inEnv, inExtendsTable, inIsFirst,
432 inFullPath, inInfo);
433 1276072 rest_path := qualifyExtends3(rest_path, env, inExtendsTable, false, inFullPath, inInfo, ep);
434 1276072 then
435 makeExtendsPath(opath, SOME(rest_path), env, ep, inIsFirst);
436
437 case (Absyn.FULLYQUALIFIED(path = rest_path), _)
438 algorithm
439 132 env := NFSCodeEnv.getEnvTopScope(inEnv);
440 132 then
441 qualifyExtends3(rest_path, env, inExtendsTable, inIsFirst, rest_path,
442 inInfo, NONE());
443
444 end match;
445 end qualifyExtends3;
446
447 protected function makeExtendsPath
448 input Option<Absyn.Path> inFirstPath;
449 input Option<Absyn.Path> inRestPath;
450 input Env inEnv;
451 input Option<Absyn.Path> inErrorPath;
452 input Boolean inIsFirst;
453 output Absyn.Path outPath;
454 algorithm
455 outPath := match(inFirstPath, inRestPath, inErrorPath, inIsFirst)
456 local
457 Absyn.Path path;
458
459 // If an error has occured, return the error path.
460 case (_, _, SOME(path), _) then path;
461 case (_, SOME(path as Absyn.QUALIFIED(name = "$E")), _, _) then path;
462
463 // If the rest of the path is fully qualified it overwrites everything before.
464 case (_, SOME(path as Absyn.FULLYQUALIFIED()), _, _) then path;
465
466 // If inFirstPath is the very first part of the path, use the environment to
467 // get the whole path.
468 case (_, _, _, true)
469 algorithm
470 592133 path := NFSCodeEnv.getEnvPath(inEnv);
471 592133 path := AbsynUtil.joinPathsOptSuffix(path, inRestPath);
472 592133 path := AbsynUtil.makeFullyQualified(path);
473 then
474 path;
475
476 // Otherwise, just join them.
477 1276038 case (SOME(path), _, _, _) then AbsynUtil.joinPathsOptSuffix(path, inRestPath);
478
479 end match;
480 end makeExtendsPath;
481
482 protected function qualifyExtendsPart
483 input String inName;
484 input Env inEnv;
485 input ExtendsTableArray inExtendsTable;
486 input Boolean inIsFirst;
487 input Absyn.Path inFullPath;
488 input SourceInfo inInfo;
489 output Option<Absyn.Path> outPath;
490 output Env outEnv;
491 output Option<Absyn.Path> outErrorPath;
492 protected
493 Option<Item> oitem;
494 Option<Env> oenv;
495 Boolean fe;
496 algorithm
497 1868533 (oitem, outPath, oenv, fe) := lookupSimpleName(inName, inEnv, inExtendsTable);
498 1868533 (outEnv, outErrorPath) := qualifyExtendsPart2(Absyn.IDENT(inName), oitem,
499 oenv, inEnv, inIsFirst, fe, inFullPath);
500 end qualifyExtendsPart;
501
502 protected function qualifyExtendsPart2
503 input Absyn.Path inPartName;
504 input Option<Item> inItem;
505 input Option<Env> inFoundEnv;
506 input Env inOriginEnv;
507 input Boolean inIsFirst;
508 input Boolean inFromExtends;
509 input Absyn.Path inFullPath;
510 output Env outEnv;
511 output Option<Absyn.Path> outErrorPath;
512 algorithm
513 (outEnv, outErrorPath) := match(inItem, inFoundEnv)
514 local
515 Item item;
516 Env env;
517 Option<Absyn.Path> ep;
518
519 case (SOME(item), SOME(env))
520 algorithm
521 1868196 ep := checkExtendsPart(inIsFirst, inFromExtends, inPartName, item,
522 inFullPath, env, inOriginEnv);
523 1868196 env := NFSCodeEnv.mergeItemEnv(item, env);
524 then
525 (env, ep);
526
527 337 else (NFSCodeEnv.emptyEnv,
528 makeExtendsError(inFullPath, inPartName, BASECLASS_NOT_FOUND_ERROR));
529 end match;
530 end qualifyExtendsPart2;
531
532 protected function makeExtendsError
533 input Absyn.Path inBaseClass;
534 input Absyn.Path inPart;
535 input String inError;
536 output Option<Absyn.Path> outError;
537 algorithm
538 outError := match inError
539 local
540 Absyn.Path path;
541
542 case _
543 algorithm
544 339 path := AbsynUtil.joinPaths(inPart, Absyn.QUALIFIED("$bc", inBaseClass));
545 339 path := Absyn.QUALIFIED("$E", Absyn.QUALIFIED(inError, path));
546 then
547 SOME(path);
548
549 end match;
550 end makeExtendsError;
551
552 protected function checkExtendsPart
553 "This function checks that part of a base class name is correct. If it is not
554 correct it returns an error path on the form $E.$N.part_path.$bc.base_class.
555 $N, where N is an integer, defined the actual error as defined by the error
556 constants at the beginning of this file. part_path is the path of the part
557 which the error occured in, and base_class is the path of the base class as
558 declared in the code. This is used by printExtendsError to print an
559 appropriate error when needed."
560 input Boolean inIsFirst;
561 input Boolean inFromExtends;
562 input Absyn.Path inPartName;
563 input Item inItem;
564 input Absyn.Path inBaseClass;
565 input Env inFoundEnv;
566 input Env inOriginEnv;
567 output Option<Absyn.Path> outErrorPath;
568 algorithm
569 outErrorPath := matchcontinue(inIsFirst, inFromExtends, inItem)
570 local
571 Absyn.Path part;
572
573 // The first part of the base class name may not be inherited.
574 case (true, true, _)
575 1 then makeExtendsError(inBaseClass, inPartName, BASECLASS_INHERITED_ERROR);
576
577 // Not inherited class, ok!
578 case (_, _, NFSCodeEnv.CLASS())
579 then NONE();
580
581 // The base class part is actually not a class but a component, which is not
582 // allowed either.
583 case (_, _, NFSCodeEnv.VAR())
584 algorithm
585 1 part := NFSCodeEnv.mergePathWithEnvPath(inPartName, inFoundEnv);
586 1 then
587 makeExtendsError(inBaseClass, part, BASECLASS_IS_VAR_ERROR);
588
589 // We shouldn't get here.
590 ✗ else makeExtendsError(inBaseClass, inPartName, BASECLASS_UNKNOWN_ERROR);
591 end matchcontinue;
592 end checkExtendsPart;
593
594 protected function splitExtendsErrorPath
595 input Absyn.Path inPath;
596 output Absyn.Path outBaseClass;
597 output Absyn.Path outPartPath;
598 algorithm
599 (outBaseClass, outPartPath) := match inPath
600 local
601 String part_str;
602 Absyn.Path part, bc;
603
604 case Absyn.QUALIFIED(part_str, Absyn.QUALIFIED("$bc", bc))
605 2 then (bc, Absyn.IDENT(part_str));
606
607 case Absyn.QUALIFIED(part_str, part)
608 algorithm
609 1 (bc, part) := splitExtendsErrorPath(part);
610 1 then
611 (bc, Absyn.QUALIFIED(part_str, part));
612
613 end match;
614 end splitExtendsErrorPath;
615
616 public function printExtendsError
617 input Absyn.Path inErrorPath;
618 input Env inEnv;
619 input SourceInfo inInfo;
620 algorithm
621 () := matchcontinue inErrorPath
622 local
623 String err_str;
624 Absyn.Path bc, part;
625 Env env;
626
627 case Absyn.QUALIFIED(name = "$E",
628 path = Absyn.QUALIFIED(name = err_str, path = bc))
629 algorithm
630 2 (bc, part) := splitExtendsErrorPath(bc);
631 2 env := NFSCodeEnv.removeExtendFromLocalScope(inErrorPath, inEnv);
632 2 printExtendsError2(err_str, bc, part, env, inInfo);
633 then
634 ();
635
636 else
637 algorithm
638 ✗ true := Flags.isSet(Flags.FAILTRACE);
639 ✗ Debug.traceln("- NFEnvExtends.printExtendsError failed to print error " +
640 AbsynUtil.pathString(inErrorPath));
641 ✗ then
642 fail();
643
644 end matchcontinue;
645 end printExtendsError;
646
647 public function printExtendsError2
648 input String inError;
649 input Absyn.Path inBaseClass;
650 input Absyn.Path inPartPath;
651 input Env inEnv;
652 input SourceInfo inInfo;
653 algorithm
654 () := matchcontinue inPartPath
655 local
656 String bc_str, env_str, part;
657 list<Extends> exts;
658 SourceInfo info;
659
660 case _
661 algorithm
662
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 true := stringEq(inError, BASECLASS_NOT_FOUND_ERROR);
663
664 ✗ bc_str := AbsynUtil.pathString(inBaseClass);
665 ✗ env_str := NFSCodeEnv.getEnvName(inEnv);
666 ✗ Error.addSourceMessage(Error.LOOKUP_BASECLASS_ERROR,
667 {bc_str, env_str}, inInfo);
668 then
669 ();
670
671 case Absyn.IDENT(part)
672 algorithm
673
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 true := stringEq(inError, BASECLASS_INHERITED_ERROR);
674
675 1 bc_str := AbsynUtil.pathString(inBaseClass);
676 1 Error.addSourceMessage(Error.INHERITED_EXTENDS, {bc_str}, inInfo);
677 1 exts := NFSCodeEnv.getEnvExtendsFromTable(inEnv);
678 1 printInheritedExtendsError(part, exts, inEnv);
679 then
680 ();
681
682 case _
683 algorithm
684
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
1 true := stringEq(inError, BASECLASS_REPLACEABLE_ERROR);
685
686 ✗ (NFSCodeEnv.CLASS(cls = SCode.CLASS(name = part, info = info)), _, _) :=
687 NFSCodeLookup.lookupFullyQualified(inPartPath, inEnv);
688 ✗ bc_str := AbsynUtil.pathString(inBaseClass);
689 ✗ Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, inInfo);
690 ✗ Error.addSourceMessage(Error.REPLACEABLE_BASE_CLASS, {part, bc_str}, info);
691 then
692 ();
693
694 case _
695 algorithm
696
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 true := stringEq(inError, BASECLASS_IS_VAR_ERROR);
697
698
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 (NFSCodeEnv.VAR(var = SCode.COMPONENT(name = part, info = info)), _, _) :=
699 NFSCodeLookup.lookupFullyQualified(inPartPath, inEnv);
700 1 bc_str := AbsynUtil.pathString(inBaseClass);
701 1 Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, info);
702 1 Error.addSourceMessage(Error.EXTEND_THROUGH_COMPONENT,
703 {part, bc_str}, inInfo);
704 then
705 ();
706
707 end matchcontinue;
708 end printExtendsError2;
709
710 protected function printInheritedExtendsError
711 input String inName;
712 input list<Extends> inExtends;
713 input Env inEnv;
714 algorithm
715 () := matchcontinue inExtends
716 local
717 list<Extends> rest_ext;
718 Extends ext;
719 Item item;
720 SourceInfo info1, info2;
721 Absyn.Path bc;
722 String bc_str;
723
724 case (ext as NFSCodeEnv.EXTENDS(baseClass = bc, info = info2)) :: rest_ext
725 algorithm
726
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 (SOME(item), _, _) := NFSCodeLookup.lookupInBaseClasses3(inName, ext,
727 inEnv, inEnv, NFSCodeLookup.IGNORE_REDECLARES(), {});
728 2 info1 := NFSCodeEnv.getItemInfo(item);
729 2 NFSCodeEnv.EXTENDS(baseClass = bc, info = info2) := ext;
730 2 bc := AbsynUtil.makeNotFullyQualified(bc);
731 2 bc_str := AbsynUtil.pathString(bc);
732 2 Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, info1);
733 2 Error.addSourceMessage(Error.EXTENDS_INHERITED_FROM_LOCAL_EXTENDS,
734 {inName, bc_str}, info2);
735 2 printInheritedExtendsError(inName, rest_ext, inEnv);
736 then
737 ();
738
739 case _ :: rest_ext
740 algorithm
741 ✗ printInheritedExtendsError(inName, rest_ext, inEnv);
742 then
743 ();
744
745 case {} then ();
746
747 end matchcontinue;
748 end printInheritedExtendsError;
749
750 protected function lookupSimpleName
751 input String inName;
752 input Env inEnv;
753 input ExtendsTableArray inExtendsTable;
754 output Option<Item> outItem;
755 output Option<Absyn.Path> outPath;
756 output Option<Env> outEnv;
757 output Boolean outFromExtends;
758 algorithm
759 (outItem, outPath, outEnv, outFromExtends) :=
760 matchcontinue inEnv
761 local
762 FrameType frame_type;
763 Env env;
764 Option<Item> opt_item;
765 Option<Env> opt_env;
766 Option<Absyn.Path> opt_path;
767 Boolean fe;
768
769 case _
770 algorithm
771 4542586 (opt_item, opt_path, opt_env, fe) := lookupInLocalScope(inName, inEnv, inExtendsTable);
772 then
773 (opt_item, opt_path, opt_env, fe);
774
775 case NFSCodeEnv.FRAME(frameType = frame_type) :: env
776 algorithm
777 2674053 NFSCodeLookup.frameNotEncapsulated(frame_type);
778 2674053 (opt_item, opt_path, opt_env, _) := lookupSimpleName(inName, env, inExtendsTable);
779 2674053 then
780 (opt_item, opt_path, opt_env, false);
781
782 337 else (NONE(), NONE(), NONE(), false);
783
784 end matchcontinue;
785 end lookupSimpleName;
786
787 protected function lookupInLocalScope
788 input String inName;
789 input Env inEnv;
790 input ExtendsTableArray inExtendsTable;
791 output Option<Item> outItem;
792 output Option<Absyn.Path> outPath;
793 output Option<Env> outEnv;
794 output Boolean outFromExtends;
795 algorithm
796 (outItem, outPath, outEnv, outFromExtends) :=
797 matchcontinue inEnv
798 local
799 Item item;
800 Env env;
801 Option<Item> oitem;
802 Option<Absyn.Path> opath;
803 Option<Env> oenv;
804 list<Extends> bcl;
805 list<Import> imps;
806
807 case _
808 algorithm
809 16809654 (item, env) := NFSCodeLookup.lookupInClass(inName, inEnv);
810 22290118 then
811 (SOME(item), SOME(Absyn.IDENT(inName)), SOME(env), false);
812
813 case NFSCodeEnv.FRAME(extendsTable = NFSCodeEnv.EXTENDS_TABLE(
814 baseClasses = bcl as _ :: _)) :: _
815 algorithm
816 2915524 (oitem, oenv) := lookupInBaseClasses(inName, bcl, inEnv, inExtendsTable);
817 6 then
818 (oitem, SOME(Absyn.IDENT(inName)), oenv, true);
819
820 case NFSCodeEnv.FRAME(importTable =
821 NFSCodeEnv.IMPORT_TABLE(hidden = false, qualifiedImports = imps)) :: _
822 algorithm
823 2695304 (oitem, opath, oenv) :=
824 lookupInQualifiedImports(inName, imps, inEnv, inExtendsTable);
825 18982 then
826 (oitem, opath, oenv, false);
827
828 case NFSCodeEnv.FRAME(importTable =
829 NFSCodeEnv.IMPORT_TABLE(hidden = false, unqualifiedImports = imps)) :: _
830 algorithm
831 2676322 (oitem, opath, oenv) :=
832 lookupInUnqualifiedImports(inName, imps, inEnv, inExtendsTable);
833 1 then
834 (oitem, opath, oenv, false);
835
836 end matchcontinue;
837 end lookupInLocalScope;
838
839 protected function lookupInBaseClasses
840 input String inName;
841 input list<Extends> inExtends;
842 input Env inEnv;
843 input ExtendsTableArray inExtendsTable;
844 output Option<Item> outItem;
845 output Option<Env> outEnv;
846 algorithm
847 (outItem, outEnv) :=
848 matchcontinue inExtends
849 local
850 Extends ext;
851 list<Extends> rest_ext;
852 Option<Extends> opt_ext;
853 Option<Item> opt_item;
854 Option<Env> opt_env;
855 Env env;
856
857 case ext :: _
858 algorithm
859 // Unhide the imports, otherwise we might not be able to find the base
860 // classes.
861 2969600 env := NFSCodeEnv.setImportTableHidden(inEnv, false);
862 2969600 opt_ext := qualifyExtends2(ext, env, inExtendsTable);
863 2969600 (opt_item, opt_env) :=
864 lookupInBaseClasses2(inName, opt_ext, env, inExtendsTable);
865 then
866 (opt_item, opt_env);
867
868 case _ :: rest_ext
869 algorithm
870 2969597 (opt_item, opt_env) :=
871 lookupInBaseClasses(inName, rest_ext, inEnv, inExtendsTable);
872 then
873 (opt_item, opt_env);
874
875 end matchcontinue;
876 end lookupInBaseClasses;
877
878 protected function lookupInBaseClasses2
879 input String inName;
880 input Option<Extends> inExtends;
881 input Env inEnv;
882 input ExtendsTableArray inExtendsTable;
883 output Option<Item> outItem;
884 output Option<Env> outEnv;
885 algorithm
886 (outItem, outEnv) := match inExtends
887 local
888 Absyn.Path bc;
889 Item item;
890 Env env;
891 Option<Item> opt_item;
892 Option<Env> opt_env;
893
894 case SOME(NFSCodeEnv.EXTENDS(baseClass = Absyn.FULLYQUALIFIED(bc)))
895 algorithm
896 2968954 (item, env) := lookupFullyQualified(bc, inEnv, inExtendsTable);
897 2968954 env := NFSCodeEnv.mergeItemEnv(item, env);
898 // Hide the imports to make sure we don't find any elements through
899 // them, since imports are not inherited.
900 2968954 env := NFSCodeEnv.setImportTableHidden(env, true);
901 2968954 (opt_item, _, opt_env, _) := lookupInLocalScope(inName, env, inExtendsTable);
902
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 then
903 (opt_item, opt_env);
904
905 end match;
906 end lookupInBaseClasses2;
907
908 protected function lookupInQualifiedImports
909 input String inName;
910 input list<Import> inImports;
911 input Env inEnv;
912 input ExtendsTableArray inExtendsTable;
913 output Option<Item> outItem;
914 output Option<Absyn.Path> outPath;
915 output Option<Env> outEnv;
916 algorithm
917 (outItem, outPath, outEnv) := matchcontinue inImports
918 local
919 Absyn.Ident name;
920 Absyn.Path path;
921 Item item;
922 list<Import> rest_imps;
923 Option<Item> opt_item;
924 Option<Absyn.Path> opt_path;
925 Option<Env> opt_env;
926 Env env;
927
928 case Absyn.NAMED_IMPORT(name = name) :: rest_imps
929 algorithm
930
4/4
✓ Branch 0 taken 28291 times.
✓ Branch 1 taken 964412 times.
✓ Branch 3 taken 18982 times.
✓ Branch 4 taken 9309 times.
992703 false := stringEqual(inName, name);
931 973721 (opt_item, opt_path, opt_env) :=
932 lookupInQualifiedImports(inName, rest_imps, inEnv, inExtendsTable);
933 then
934 (opt_item, opt_path, opt_env);
935
936 case Absyn.NAMED_IMPORT(name = name, path = path) :: _
937 algorithm
938
4/4
✓ Branch 0 taken 24225 times.
✓ Branch 1 taken 960328 times.
✓ Branch 3 taken 5243 times.
✓ Branch 4 taken 18982 times.
984553 true := stringEqual(inName, name);
939 18982 (item, env) := lookupFullyQualified(path, inEnv, inExtendsTable);
940 18982 path := NFSCodeEnv.prefixIdentWithEnv(inName, env);
941 18982 path := AbsynUtil.makeFullyQualified(path);
942 18982 then
943 (SOME(item), SOME(path), SOME(env));
944
945 case Absyn.NAMED_IMPORT(name = name) :: _
946 algorithm
947
3/4
✓ Branch 0 taken 5243 times.
✓ Branch 1 taken 960328 times.
✓ Branch 3 taken 5243 times.
✗ Branch 4 not taken.
965571 true := stringEqual(inName, name);
948 ✗ then
949 (NONE(), NONE(), NONE());
950
951 end matchcontinue;
952 end lookupInQualifiedImports;
953
954 protected function lookupInUnqualifiedImports
955 input Absyn.Ident inName;
956 input list<Import> inImports;
957 input Env inEnv;
958 input ExtendsTableArray inExtendsTable;
959 output Option<Item> outItem;
960 output Option<Absyn.Path> outPath;
961 output Option<Env> outEnv;
962 algorithm
963 (outItem, outPath, outEnv) := matchcontinue inImports
964 local
965 Item item;
966 Absyn.Path path;
967 list<Import> rest_imps;
968 Env env;
969 Option<Item> opt_item;
970 Option<Absyn.Path> opt_path;
971 Option<Env> opt_env;
972
973 case Absyn.UNQUAL_IMPORT(path = path) :: _
974 algorithm
975 2269 (item, env) := lookupFullyQualified(path, inEnv, inExtendsTable);
976 2269 env := NFSCodeEnv.mergeItemEnv(item, env);
977 2269 (item, env) := lookupFullyQualified2(Absyn.IDENT(inName), env, inExtendsTable);
978 1 path := NFSCodeEnv.prefixIdentWithEnv(inName, env);
979 1 path := AbsynUtil.makeFullyQualified(path);
980 1 then
981 (SOME(item), SOME(path), SOME(env));
982
983 case _ :: rest_imps
984 algorithm
985 2268 (opt_item, opt_path, opt_env) :=
986 lookupInUnqualifiedImports(inName, rest_imps, inEnv, inExtendsTable);
987 then
988 (opt_item, opt_path, opt_env);
989
990 end matchcontinue;
991 end lookupInUnqualifiedImports;
992
993 protected function lookupFullyQualified
994 input Absyn.Path inName;
995 input Env inEnv;
996 input ExtendsTableArray inExtendsTable;
997 output Item outItem;
998 output Env outEnv;
999 protected
1000 Env env;
1001 algorithm
1002 2990205 env := NFSCodeEnv.getEnvTopScope(inEnv);
1003 2990205 (outItem, outEnv) := lookupFullyQualified2(inName, env, inExtendsTable);
1004 end lookupFullyQualified;
1005
1006 protected function lookupFullyQualified2
1007 input Absyn.Path inName;
1008 input Env inEnv;
1009 input ExtendsTableArray inExtendsTable;
1010 output Item outItem;
1011 output Env outEnv;
1012 algorithm
1013 (outItem, outEnv) := match inName
1014 local
1015 String name;
1016 Absyn.Path rest_path;
1017 Item item;
1018 Env env;
1019
1020 case Absyn.IDENT(name = name)
1021 algorithm
1022
5/10
✗ Branch 1 not taken.
✓ Branch 2 taken 2990206 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2990206 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2990206 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2990206 times.
✓ Branch 9 taken 2990206 times.
✗ Branch 10 not taken.
2992474 (SOME(item), _, SOME(env), _) :=
1023 lookupInLocalScope(name, inEnv, inExtendsTable);
1024 then
1025 (item, env);
1026
1027 case Absyn.QUALIFIED(name = name, path = rest_path)
1028 algorithm
1029
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 6305640 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6305640 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6305640 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6305640 times.
6305640 (SOME(item), _, SOME(env), _) :=
1030 lookupInLocalScope(name, inEnv, inExtendsTable);
1031 6305640 env := NFSCodeEnv.mergeItemEnv(item, env);
1032 6305640 (item, env) := lookupFullyQualified2(rest_path, env, inExtendsTable);
1033 then
1034 (item, env);
1035
1036 end match;
1037 end lookupFullyQualified2;
1038
1039 protected function createExtendsTable
1040 input Integer inSize;
1041 output ExtendsTableArray outTable;
1042 algorithm
1043 1103 outTable := arrayCreate(inSize, NO_EXTENDS());
1044 end createExtendsTable;
1045
1046 protected function lookupQualifiedExtends
1047 input Integer inIndex;
1048 input ExtendsTableArray inExtendsTable;
1049 output Option<Extends> outExtends;
1050 protected
1051 ExtendsWrapper ext;
1052 algorithm
1053 3561751 ext := arrayGet(inExtendsTable, inIndex);
1054 3561751 outExtends := lookupQualifiedExtends2(ext, inExtendsTable);
1055 end lookupQualifiedExtends;
1056
1057 protected function lookupQualifiedExtends2
1058 input ExtendsWrapper inExtends;
1059 input ExtendsTableArray inExtendsTable;
1060 output Option<Extends> outExtends;
1061 algorithm
1062 outExtends := match inExtends
1063 local
1064 Extends ext;
1065
1066 case QUALIFIED_EXTENDS(ext = ext) then SOME(ext);
1067
1068 case UNQUALIFIED_EXTENDS(ext = NFSCodeEnv.EXTENDS())
1069 then NONE();
1070
1071 end match;
1072 end lookupQualifiedExtends2;
1073
1074 protected function addUnqualifiedToTable
1075 input Extends inExtends;
1076 input Integer inIndex;
1077 input ExtendsTableArray inExtendsTable;
1078 algorithm
1079 592472 arrayUpdate(inExtendsTable, inIndex, UNQUALIFIED_EXTENDS(inExtends));
1080 end addUnqualifiedToTable;
1081
1082 protected function updateQualifiedInTable
1083 input Extends inExtends;
1084 input Integer inIndex;
1085 input ExtendsTableArray inExtendsTable;
1086 algorithm
1087 592472 arrayUpdate(inExtendsTable, inIndex, QUALIFIED_EXTENDS(inExtends));
1088 end updateQualifiedInTable;
1089
1090 protected function update2
1091 input Env inEnv;
1092 output Env outEnv;
1093 protected
1094 Env env, rest_env;
1095 Option<String> name;
1096 FrameType ty;
1097 EnvTree.Tree tree;
1098 list<Extends> bcl;
1099 list<SCode.Element> re;
1100 NFSCodeEnv.ImportTable imps;
1101 Option<Mutable<Boolean>> iu;
1102 algorithm
1103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1456771 times.
1456771 NFSCodeEnv.FRAME(name, ty, tree,
1104 NFSCodeEnv.EXTENDS_TABLE(bcl, re, _), imps, iu) :: rest_env := inEnv;
1105 1456771 tree := EnvTree.map(tree, function update3(inEnv = inEnv));
1106 1456769 env := NFSCodeEnv.FRAME(name, ty, tree,
1107 NFSCodeEnv.EXTENDS_TABLE(bcl, {}, NONE()), imps, iu) :: rest_env;
1108 1456769 outEnv := NFSCodeFlattenRedeclare.addElementRedeclarationsToEnv(re, env);
1109 end update2;
1110
1111 protected function update3
1112 input String name;
1113 input output Item item;
1114 input Env inEnv;
1115 algorithm
1116 () := match item
1117 local
1118 Env env;
1119 SCode.Element cls;
1120 ClassType cls_ty;
1121 Frame cls_env;
1122
1123 case NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty)
1124 algorithm
1125 // Enter the class' frame and update the class extends in it.
1126 1455668 env := NFSCodeEnv.enterFrame(cls_env, inEnv);
1127 1455668 (cls, env) := updateClassExtends(cls, env, cls_ty);
1128 // Call update2 on the class' environment to update the extends.
1129
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1455666 times.
1455668 cls_env :: _ := update2(env);
1130 // Rebuild the class item with the updated information.
1131 1455666 item := NFSCodeEnv.CLASS(cls, {cls_env}, cls_ty);
1132 then
1133 ();
1134
1135 else ();
1136 end match;
1137 end update3;
1138
1139 protected function updateClassExtends
1140 input SCode.Element inClass;
1141 input Env inEnv;
1142 input ClassType inClassType;
1143 output SCode.Element outClass;
1144 output Env outEnv;
1145 algorithm
1146 (outClass, outEnv) := match(inEnv, inClassType)
1147 local
1148 String name;
1149 Env env;
1150 SCode.Mod mods;
1151 SourceInfo info;
1152 SCode.Element cls, ext;
1153
1154 case (NFSCodeEnv.FRAME(name = SOME(name),
1155 extendsTable = NFSCodeEnv.EXTENDS_TABLE(classExtendsInfo = SOME(ext))) :: _, NFSCodeEnv.CLASS_EXTENDS())
1156 algorithm
1157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38783 times.
38783 SCode.EXTENDS(modifications = mods, info = info) := ext;
1158 38783 (cls, env) := updateClassExtends2(inClass, name, mods, info, inEnv);
1159 then
1160 (cls, env);
1161
1162 1416885 else (inClass, inEnv);
1163 end match;
1164 end updateClassExtends;
1165
1166 protected function updateClassExtends2
1167 input SCode.Element inClass;
1168 input String inName;
1169 input SCode.Mod inMods;
1170 input SourceInfo inInfo;
1171 input Env inEnv;
1172 output SCode.Element outClass;
1173 output Env outEnv;
1174 algorithm
1175 (outClass, outEnv) := matchcontinue inEnv
1176 local
1177 SCode.Element ext;
1178 Frame cls_frame;
1179 Env env;
1180 SCode.Element cls;
1181 Absyn.Path path;
1182
1183 case cls_frame :: env
1184 algorithm
1185 38783 (path,_) := lookupClassExtendsBaseClass(inName, env, inInfo);
1186 38782 ext := SCode.EXTENDS(path, SCode.PUBLIC(), inMods, NONE(), inInfo);
1187
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 38782 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38782 times.
38782 {cls_frame} := NFSCodeEnv.extendEnvWithExtends(ext, {cls_frame});
1188 38782 cls := SCodeUtil.addElementToClass(ext, inClass);
1189 then
1190 (cls, cls_frame :: env);
1191
1192 else (inClass, inEnv);
1193 end matchcontinue;
1194 end updateClassExtends2;
1195
1196 protected function lookupClassExtendsBaseClass
1197 "This function takes the name of a base class and looks up that name suffixed
1198 with the base class suffix defined in NFSCodeEnv. I.e. it looks up the real base
1199 class of a class extends, and not the alias introduced when adding replaceable
1200 classes to the environment in NFSCodeEnv.extendEnvWithClassDef. It returns the
1201 path and the item for that base class."
1202 input String inName;
1203 input Env inEnv;
1204 input SourceInfo inInfo;
1205 output Absyn.Path outPath;
1206 output Item outItem;
1207 algorithm
1208 (outPath, outItem) := matchcontinue inInfo
1209 local
1210 Absyn.Path path;
1211 Item item;
1212 String basename;
1213
1214 // Add the base class suffix to the name and try to look it up.
1215 case _
1216 algorithm
1217 38783 basename := inName + NFSCodeEnv.BASE_CLASS_SUFFIX;
1218 38783 (item, _) := NFSCodeLookup.lookupInheritedName(basename, inEnv);
1219 // Use a special $ce qualified so that we can find the correct class
1220 // with NFSCodeLookup.lookupBaseClassName.
1221 38782 path := Absyn.QUALIFIED("$ce", Absyn.IDENT(basename));
1222 then
1223 (path, item);
1224
1225 // The previous case will fail if we try to class extend a
1226 // non-replaceable class, because they don't have aliases. To get the
1227 // correct error message later we look the class up via the non-alias name
1228 // instead and return that result if found.
1229 case _
1230 algorithm
1231 1 (item, _) := NFSCodeLookup.lookupInheritedName(inName, inEnv);
1232 ✗ path := Absyn.IDENT(inName);
1233 then
1234 (path, item);
1235
1236 // If the class doesn't even exist, show an error.
1237 else
1238 algorithm
1239 1 Error.addSourceMessage(Error.INVALID_REDECLARATION_OF_CLASS,
1240 {inName}, inInfo);
1241 1 then
1242 fail();
1243
1244 end matchcontinue;
1245 end lookupClassExtendsBaseClass;
1246
1247 public function extendEnvWithClassExtends
1248 "Extends the environment with the given class extends element."
1249 input SCode.Element inClassExtends;
1250 input Env inEnv;
1251 output Env outEnv;
1252 algorithm
1253 outEnv := match inClassExtends
1254 local
1255 SCode.Partial pp;
1256 SCode.Encapsulated ep;
1257 SCode.Restriction res;
1258 SCode.Prefixes prefixes;
1259 SourceInfo info;
1260 Env env, cls_env;
1261 SCode.Mod mods;
1262 SCode.ClassDef cdef;
1263 SCode.Element cls, ext;
1264 String name, el_str, env_str, err_msg;
1265 SCode.Comment cmt;
1266
1267 // When a 'class extends X' is encountered we insert a 'class X extends
1268 // BaseClass.X' into the environment, with the same elements as the class
1269 // extends clause. BaseClass is the class that class X is inherited from.
1270 // This allows us to look up elements in class extends, because lookup can
1271 // handle normal extends. This is the first phase where the CLASS_EXTENDS is
1272 // converted to a PARTS and added to the environment, and the extends is
1273 // added to the class environment's extends table. The rest of the work is
1274 // done later in updateClassExtends when we have a complete environment.
1275 case SCode.CLASS(
1276 name = name,
1277 prefixes = prefixes,
1278 encapsulatedPrefix = ep,
1279 partialPrefix = pp,
1280 restriction = res,
1281 classDef = SCode.CLASS_EXTENDS(
1282 modifications = mods,
1283 composition = cdef),
1284 cmt=cmt, info = info)
1285 algorithm
1286 // Construct a new PARTS class with the data from the class extends.
1287 38783 cls := SCode.CLASS(name, prefixes, ep, pp, res, cdef, cmt, info);
1288
1289 // Construct the class environment and add the new extends to it.
1290 38783 cls_env := NFSCodeEnv.makeClassEnvironment(cls, false);
1291 38783 ext := SCode.EXTENDS(Absyn.IDENT(name), SCode.PUBLIC(), mods, NONE(), info);
1292 38783 cls_env := addClassExtendsInfoToEnv(ext, cls_env);
1293
1294 // Finally add the class to the environment.
1295 38783 env := NFSCodeEnv.extendEnvWithItem(
1296 NFSCodeEnv.newClassItem(cls, cls_env, NFSCodeEnv.CLASS_EXTENDS()), inEnv, name);
1297 then env;
1298
1299 case _
1300 algorithm
1301 ✗ info := SCodeUtil.elementInfo(inClassExtends);
1302 ✗ el_str := SCodeDump.unparseElementStr(inClassExtends,SCodeDump.defaultOptions);
1303 ✗ env_str := NFSCodeEnv.getEnvName(inEnv);
1304 ✗ err_msg := "NFSCodeFlattenRedeclare.extendEnvWithClassExtends failed on unknown element " +
1305 el_str + " in " + env_str;
1306 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR, {err_msg}, info);
1307 ✗ then
1308 fail();
1309
1310 end match;
1311 end extendEnvWithClassExtends;
1312
1313 protected function addClassExtendsInfoToEnv
1314 "Adds a class extends to the environment."
1315 input SCode.Element inClassExtends;
1316 input Env inEnv;
1317 output Env outEnv;
1318 algorithm
1319 outEnv := matchcontinue inEnv
1320 local
1321 list<Extends> bcl;
1322 list<SCode.Element> re;
1323 String estr;
1324 NFSCodeEnv.ExtendsTable ext;
1325
1326 case _
1327 algorithm
1328
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 38783 times.
✓ Branch 3 taken 38783 times.
✗ Branch 4 not taken.
38783 NFSCodeEnv.EXTENDS_TABLE(bcl, re, NONE()) :=
1329 NFSCodeEnv.getEnvExtendsTable(inEnv);
1330 38783 ext := NFSCodeEnv.EXTENDS_TABLE(bcl, re, SOME(inClassExtends));
1331 38783 then
1332 NFSCodeEnv.setEnvExtendsTable(ext, inEnv);
1333
1334 else
1335 algorithm
1336 estr := "- NFEnvExtends.addClassExtendsInfoToEnv: Trying to overwrite " +
1337 "existing class extends information, this should not happen!.";
1338 ✗ Error.addMessage(Error.INTERNAL_ERROR, {estr});
1339 ✗ then
1340 fail();
1341
1342 end matchcontinue;
1343 end addClassExtendsInfoToEnv;
1344
1345 annotation(__OpenModelica_Interface="frontend");
1346 end NFEnvExtends;
1347