Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.9% 245 / 0 / 282
Functions: -% 0 / 1 / 1
Branches: 73.7% 112 / 0 / 152

OMCompiler/Compiler/NFFrontEnd/NFLookup.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 NFLookup
37 " file: NFLookup.mo
38 package: NFLookup
39 description: Lookup functions for NFInst
40 "
41
42 import Absyn;
43 import AbsynUtil;
44 import Attributes = NFAttributes;
45 import SCode;
46 import Dump;
47 import ErrorTypes;
48 import Global;
49 import NFBuiltin;
50 import Inst = NFInst;
51 import Class = NFClass;
52 import NFInstNode.InstNode;
53 import NFInstNode;
54 import NFLookupState.LookupState;
55 import Type = NFType;
56 import ComponentRef = NFComponentRef;
57 import InstContext = NFInstContext;
58 import InstNodeType = NFInstNode.InstNodeType;
59
60 protected
61 import NFInstNode.NodeTree;
62 import NFInstNode.CachedData;
63 import Component = NFComponent;
64 import Subscript = NFSubscript;
65 import ComplexType = NFComplexType;
66 import Error;
67 import ErrorExt;
68 import UnorderedMap;
69 import Modifier = NFModifier;
70 import BackendInterface;
71 import Settings;
72 import Testsuite;
73 import AbsynToSCode;
74 import NFClassTree.ClassTree;
75 import SCodeUtil;
76 import System;
77
78 public
79 type MatchType = enumeration(FOUND, NOT_FOUND, PARTIAL);
80
81 function lookupClassName
82 input Absyn.Path name;
83 input InstNode scope;
84 input InstContext.Type context;
85 input SourceInfo info;
86 input Boolean checkAccessViolations = true;
87 output InstNode node;
88 output list<InstNode> prefixes "The classes the name was looked up through, see lookupName.";
89 protected
90 LookupState state;
91 algorithm
92 965120 (node, state, prefixes) := lookupNameWithError(name, scope, context, info, Error.LOOKUP_ERROR, checkAccessViolations);
93 965088 LookupState.assertClass(state, node, name, context, info);
94 end lookupClassName;
95
96 function lookupBaseClassName
97 input Absyn.Path name;
98 input InstNode scope;
99 input InstContext.Type context;
100 input SourceInfo info;
101 output list<InstNode> nodes;
102 protected
103 LookupState state;
104 algorithm
105 try
106 183797 (nodes, state) := lookupNames(name, scope, context);
107 else
108 9 Error.addSourceMessage(Error.LOOKUP_BASECLASS_ERROR,
109 {AbsynUtil.pathString(name), InstNode.scopeName(scope)}, info);
110 3 fail();
111 end try;
112
113 183794 LookupState.assertClass(state, listHead(nodes), name, context, info);
114 end lookupBaseClassName;
115
116 function lookupComponent
117 input Absyn.ComponentRef cref;
118 input InstNode scope "The scope to look in.";
119 input InstContext.Type context;
120 input SourceInfo info;
121 output ComponentRef foundCref;
122 output InstNode foundScope "The scope the cref was found in.";
123 protected
124 LookupState state;
125 InstNode node;
126 algorithm
127 try
128 1149963 (foundCref, foundScope, state) := lookupCref(cref, scope, context);
129 1149959 node := ComponentRef.node(foundCref);
130
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1149959 times.
1149959 false := InstNode.isName(node);
131 else
132 12 Error.addSourceMessageAndFail(Error.LOOKUP_VARIABLE_ERROR,
133 {Dump.printComponentRefStr(cref), InstNode.scopeName(scope)}, info);
134 end try;
135
136 1149959 state := fixTypenameState(node, state, context);
137 1149959 LookupState.assertComponent(state, node, cref, context, info);
138 end lookupComponent;
139
140 function lookupConnector
141 input Absyn.ComponentRef cref;
142 input InstNode scope "The scope to look in.";
143 input InstContext.Type context;
144 input SourceInfo info;
145 output ComponentRef foundCref;
146 output InstNode foundScope "The scope the cref was found in.";
147 protected
148 LookupState state;
149 InstNode node;
150 algorithm
151 try
152 26792 (foundCref, foundScope, state) := lookupCref(cref, scope, context);
153 else
154 6 Error.addSourceMessageAndFail(Error.LOOKUP_VARIABLE_ERROR,
155 {Dump.printComponentRefStr(cref), InstNode.scopeName(scope)}, info);
156 end try;
157
158 26790 node := ComponentRef.node(foundCref);
159 26790 state := fixTypenameState(node, state, context);
160 26790 LookupState.assertComponent(state, node, cref, context, info);
161 end lookupConnector;
162
163 function fixTypenameState
164 input InstNode component;
165 input output LookupState state;
166 input InstContext.Type context;
167 protected
168 Type ty;
169 algorithm
170
2/2
✓ Branch 1 taken 1176446 times.
✓ Branch 2 taken 303 times.
1176749 if InstNode.isClass(component) then
171 303 ty := InstNode.getType(Inst.expand(component, context));
172
173 state := match ty
174 case Type.ENUMERATION() then LookupState.COMP();
175 case Type.BOOLEAN() then LookupState.COMP();
176 else state;
177 end match;
178 end if;
179 end fixTypenameState;
180
181 function lookupLocalComponent
182 "Looks up a component in the local scope, without searching in any enclosing
183 scopes. The found scope is returned since it can be different from the given
184 scope in the case where the cref refers to an outer component."
185 input Absyn.ComponentRef cref;
186 input InstNode scope "The scope to look in.";
187 input InstContext.Type context;
188 input SourceInfo info;
189 output ComponentRef foundCref;
190 output InstNode foundScope "The scope the cref was found in.";
191 protected
192 LookupState state;
193 InstNode node;
194 algorithm
195 1421 (foundCref, foundScope, state) := lookupLocalCref(cref, scope, context, info);
196 1421 LookupState.assertComponent(state, ComponentRef.node(foundCref), cref, context, info);
197 end lookupLocalComponent;
198
199 function lookupFunctionName
200 input Absyn.ComponentRef cref;
201 input InstNode scope "The scope to look in.";
202 input InstContext.Type context;
203 input SourceInfo info;
204 output ComponentRef foundCref;
205 output InstNode foundScope;
206 protected
207 LookupState state;
208 InstNode node;
209 algorithm
210 try
211 109929 (foundCref, foundScope, state) := lookupCref(cref, scope, context);
212 109926 node := ComponentRef.node(foundCref);
213
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 109926 times.
109926 false := InstNode.isName(node);
214 else
215 9 Error.addSourceMessageAndFail(Error.LOOKUP_FUNCTION_ERROR,
216 {Dump.printComponentRefStr(cref), InstNode.scopeName(scope)}, info);
217 end try;
218
219 109926 (foundCref, state) := fixExternalObjectCall(node, foundCref, state);
220 109926 LookupState.assertFunction(state, node, cref, context, info);
221 end lookupFunctionName;
222
223 function lookupFunctionNameSilent
224 input Absyn.ComponentRef cref;
225 input InstNode scope "The scope to look in.";
226 input InstContext.Type context;
227 output ComponentRef foundCref;
228 output InstNode foundScope;
229 protected
230 LookupState state;
231 InstNode node;
232 algorithm
233 1998 (foundCref, foundScope, state) := lookupCref(cref, scope, context);
234 1983 node := ComponentRef.node(foundCref);
235 1983 (foundCref, state) := fixExternalObjectCall(node, foundCref, state);
236
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1983 times.
1983 true := LookupState.isFunction(state, node);
237 end lookupFunctionNameSilent;
238
239 function fixExternalObjectCall
240 "Changes calls to external objects so that the constructor is called instead,
241 i.e. a call such as
242 'ExtObj eo = ExtObj(...)'
243 is changed to
244 'ExtObj eo = ExtObj.constructor(...)'"
245 input InstNode node;
246 input output ComponentRef cref;
247 input output LookupState state;
248 protected
249 Class cls;
250 NFInstNode.ScopeRef constructor;
251 algorithm
252 // If it's not a class it can't be an external object.
253
2/2
✓ Branch 1 taken 107791 times.
✓ Branch 2 taken 4118 times.
111909 if not LookupState.isClass(state) then
254 107791 return;
255 end if;
256
257 // External objects are identified by extending from ExternalObject, so the
258 // node needs to be expanded before we know whether it's an external object or
259 // not. Components are instantiated before their bindings, so in proper models
260 // we shouldn't get any non-expanded external objects here. But to avoid
261 // getting weird errors in erroneous models we make sure it's expanded anyway.
262 4118 Inst.expand(node, NFInstContext.NO_CONTEXT);
263 4118 cls := InstNode.getClass(node);
264
265 () := match cls
266 case Class.PARTIAL_BUILTIN(ty = Type.COMPLEX(complexTy =
267 ComplexType.EXTERNAL_OBJECT(constructor = constructor)))
268 algorithm
269 42 cref := ComponentRef.prefixCref(InstNode.borrow(constructor), Type.UNKNOWN(), {}, cref);
270 state := LookupState.FUNC();
271 then
272 ();
273
274 else ();
275 end match;
276 end fixExternalObjectCall;
277
278 function lookupImport
279 input Absyn.Path name;
280 input InstNode scope;
281 input SourceInfo info;
282 output InstNode element;
283 protected
284 LookupState state;
285 algorithm
286 10992 (element, state) := lookupNameWithError(name, InstNode.topScope(scope),
287 NFInstContext.NO_CONTEXT, info, Error.LOOKUP_IMPORT_ERROR);
288 10991 LookupState.assertImport(state, element, name, info);
289 end lookupImport;
290
291 function lookupCrefWithError
292 input Absyn.ComponentRef cref;
293 input InstNode scope;
294 input InstContext.Type context;
295 input SourceInfo info;
296 input ErrorTypes.Message errMsg;
297 output ComponentRef foundCref;
298 output InstNode foundScope;
299 output LookupState state;
300 algorithm
301 try
302 ✗ (foundCref, foundScope, state) := lookupCref(cref, scope, context);
303 else
304 ✗ Error.addSourceMessage(errMsg,
305 {Dump.printComponentRefStr(cref), InstNode.scopeName(scope)}, info);
306 ✗ fail();
307 end try;
308 end lookupCrefWithError;
309
310 function lookupCref
311 "This function will look up an Absyn.ComponentRef in the given scope, and
312 construct a ComponentRef from the found nodes. The scope where the first part
313 of the cref was found will also be returned."
314 input Absyn.ComponentRef cref;
315 input InstNode scope "The scope to look in.";
316 input InstContext.Type context;
317 output ComponentRef foundCref;
318 output InstNode foundScope "The scope where the first part of the cref was found.";
319 output LookupState state;
320 protected
321 InstNode node;
322 Boolean in_enclosing, is_iterator;
323 algorithm
324 (foundCref, foundScope, state) := match cref
325 case Absyn.ComponentRef.CREF_IDENT()
326 algorithm
327 893455 (_, foundCref, foundScope, in_enclosing, _, state) := lookupSimpleCref(cref.name, cref.subscripts, scope, context);
328 893437 state := LookupState.checkCrefVariability(foundCref, in_enclosing, context, state);
329 893437 then
330 (foundCref, foundScope, state);
331
332 case Absyn.ComponentRef.CREF_QUAL()
333 algorithm
334 395227 (node, foundCref, foundScope, in_enclosing, is_iterator, state) := lookupSimpleCref(cref.name, cref.subscripts, scope, context);
335 395226 (foundCref, foundScope, state) :=
336 lookupCrefInNode(cref.componentRef, node, is_iterator, foundCref, foundScope, state, context);
337 395221 state := LookupState.checkCrefVariability(foundCref, in_enclosing, context, state);
338 395221 then
339 (foundCref, foundScope, state);
340
341 case Absyn.ComponentRef.CREF_FULLYQUALIFIED()
342 7663 then lookupCref(cref.componentRef, InstNode.topScope(scope), context);
343
344 case Absyn.ComponentRef.WILD()
345 then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP());
346
347 case Absyn.ComponentRef.ALLWILD()
348 then (ComponentRef.WILD(), scope, LookupState.PREDEF_COMP());
349 end match;
350 end lookupCref;
351
352 function lookupLocalCref
353 "Looks up a cref in the local scope without going into any enclosing scopes."
354 input Absyn.ComponentRef cref;
355 input InstNode scope "The scope to look in.";
356 input InstContext.Type context;
357 input SourceInfo info;
358 output ComponentRef foundCref;
359 output InstNode foundScope "The scope where the first part of the cref was found.";
360 output LookupState state;
361 protected
362 InstNode node;
363 Boolean is_iterator;
364 algorithm
365 (foundCref, foundScope, state) := matchcontinue cref
366 case Absyn.ComponentRef.CREF_IDENT()
367 algorithm
368 1506 (node, foundScope) := lookupLocalSimpleCref(cref.name, scope);
369 1506 state := LookupState.nodeState(node);
370 1506 then
371 (ComponentRef.fromAbsyn(node, cref.subscripts), foundScope, state);
372
373 case Absyn.ComponentRef.CREF_QUAL()
374 algorithm
375 1 (node, foundScope, is_iterator) := lookupLocalSimpleCref(cref.name, scope);
376 1 state := LookupState.nodeState(node);
377 1 foundCref := ComponentRef.fromAbsyn(node, cref.subscripts, isIterator = is_iterator);
378 1 (foundCref, foundScope, state) :=
379 lookupCrefInNode(cref.componentRef, node, is_iterator, foundCref, foundScope, state, context);
380 then
381 (foundCref, foundScope, state);
382
383 else
384 algorithm
385 ✗ Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR,
386 {Dump.printComponentRefStr(cref), InstNode.scopeName(scope)}, info);
387 ✗ then
388 fail();
389 end matchcontinue;
390 end lookupLocalCref;
391
392 function lookupInner
393 "Looks up the corresponding inner node given an outer node."
394 input InstNode outerNode;
395 input InstNode scope;
396 output InstNode innerNode;
397 protected
398 String name = InstNode.name(outerNode);
399 InstNode cur_scope = scope;
400 InstNode prev_scope = scope;
401 algorithm
402
2/2
✓ Branch 1 taken 5898 times.
✓ Branch 2 taken 153 times.
6051 while not InstNode.isEmpty(cur_scope) loop
403 try
404 // Check if we have an element with the same name as the outer node in this scope.
405 5898 innerNode := InstNode.resolveOuter(Class.lookupElement(name, InstNode.getClass(cur_scope)));
406
2/2
✓ Branch 1 taken 714 times.
✓ Branch 2 taken 1643 times.
2357 true := InstNode.isInner(innerNode);
407 1643 return;
408 else
409
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 4227 times.
4255 if InstNode.isRootClass(cur_scope) then
410 // Stop looking if we reach the root class.
411 28 prev_scope := InstNode.topScope(cur_scope);
412 cur_scope := InstNode.EMPTY_NODE();
413 else
414 // Otherwise continue looking in the instance parent's scope.
415 4227 prev_scope := cur_scope;
416 4227 cur_scope := InstNode.instanceParent(cur_scope);
417 end if;
418 end try;
419 end while;
420
421 // No inner found, try to generate one.
422 153 innerNode := generateInner(outerNode, InstNode.topScope(prev_scope));
423 end lookupInner;
424
425 function lookupLocalSimpleName
426 "Looks up a name in the given scope, without continuing the search in any
427 enclosing scopes if the name isn't found."
428 input String name;
429 input InstNode scope;
430 output InstNode node;
431 output Boolean isImport;
432 algorithm
433 3924313 (node, isImport) := Class.lookupElement(name, InstNode.getClass(scope));
434 1638481 node := InstNode.resolveInner(node);
435 end lookupLocalSimpleName;
436
437 function lookupSimpleName
438 input String name;
439 input InstNode scope;
440 input InstContext.Type context;
441 output InstNode node;
442 output Boolean selfReference = false;
443 protected
444 InstNode cur_scope = scope;
445 Boolean require_builtin = false;
446 Boolean loaded = false;
447 algorithm
448
2/2
✓ Branch 1 taken 753 times.
✓ Branch 2 taken 753287 times.
754040 if InstContext.inAnnotation(context) then
449 // If in an annotation context, check the annotation environment first.
450 try
451 753 node := lookupLocalSimpleName(name, InstNode.annotationScope(scope));
452 394 return;
453 else
454 end try;
455 end if;
456
457 // Look for the name in each enclosing scope, until it's either found or we
458 // run out of scopes.
459 2061918 for i in 1:Global.recursionDepthLimit loop
460 try
461 2815564 node := lookupLocalSimpleName(name, cur_scope);
462
463
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 554717 times.
554844 if require_builtin then
464
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 127 times.
127 true := InstNode.isBuiltin(node);
465 end if;
466
467 753270 return;
468 else
469 // If the scope is encapsulated, continue looking among the builtin
470 // classes in the top scope.
471
2/2
✓ Branch 1 taken 129 times.
✓ Branch 2 taken 2260591 times.
2260720 if InstNode.isEncapsulated(cur_scope) then
472 // Do parentScope first to avoid an infinite loop if we're already in the top scope.
473 129 cur_scope := InstNode.topScope(InstNode.parentScope(cur_scope));
474 require_builtin := true;
475 elseif name == InstNode.name(cur_scope) and InstNode.isClass(cur_scope) or
476 name == InstNode.name(InstNode.classScope(cur_scope)) then
477 // If the scope has the same name as we're looking for we can just return it.
478 198426 node := InstNode.classScope(cur_scope);
479 selfReference := true;
480 198426 return;
481 else
482
4/4
✓ Branch 1 taken 754 times.
✓ Branch 2 taken 2061411 times.
✓ Branch 3 taken 378 times.
✓ Branch 4 taken 376 times.
2062165 if InstNode.isTopScope(cur_scope) and not loaded and not require_builtin then
483 // If the name couldn't be found in any scope, try to load a library
484 // with that name and then try to look it up in the top scope again.
485 378 loaded := true;
486 378 loadLibrary(name, cur_scope);
487 else
488 // Otherwise, continue in the enclosing scope.
489 2061787 cur_scope := InstNode.parentScope(cur_scope);
490 end if;
491 end if;
492 end try;
493 end for;
494
495 ✗ Error.addMessage(Error.RECURSION_DEPTH_REACHED,
496 {String(Global.recursionDepthLimit), InstNode.name(scope)});
497 ✗ fail();
498 end lookupSimpleName;
499
500 function lookupSimpleNameRootPath
501 "Returns the qualified path needed to find the given name in the given scope
502 that's either a root class or a class somewhere inside a root class. If the
503 name is found outside the root class it's fully qualified, otherwise it's
504 returned as it is."
505 input String name;
506 input InstNode scope;
507 input InstContext.Type context;
508 output Absyn.Path path;
509 protected
510 InstNode node, cur_scope = scope;
511 Boolean in_root_class = true;
512 algorithm
513
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 if InstContext.inAnnotation(context) then
514 try
515 ✗ lookupLocalSimpleName(name, InstNode.annotationScope(scope));
516 // Name refers to builtin annotation that shouldn't be qualified.
517 ✗ path := Absyn.Path.IDENT(name);
518 ✗ return;
519 else
520 end try;
521 end if;
522
523 36 for i in 1:Global.recursionDepthLimit loop
524 try
525 58 node := Class.lookupElement(name, InstNode.getClass(cur_scope));
526
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if in_root_class then
528 // If we're still inside the root class, then the name doesn't need to be qualified.
529 ✗ path := Absyn.Path.IDENT(name);
530 else
531 // Otherwise, fully qualify the path.
532 11 path := AbsynUtil.makeFullyQualified(InstNode.fullPath(node));
533 end if;
534
535 22 return;
536 else
537
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
47 if InstNode.isEncapsulated(cur_scope) then
538 // If the scope is encapsulated then the name can only refer to builtin
539 // classes, which are already fully qualified.
540 ✗ path := Absyn.Path.IDENT(name);
541 ✗ return;
542 elseif name == InstNode.name(cur_scope) and InstNode.isClass(cur_scope) then
543 // The current scope is the class we're looking for.
544 ✗ path := if in_root_class then Absyn.Path.IDENT(name) else
545 AbsynUtil.makeFullyQualified(InstNode.fullPath(cur_scope));
546 ✗ return;
547 elseif InstNode.isTopScope(cur_scope) then
548 // If we reach the top scope then the name is either already fully
549 // qualified or couldn't be found, in either case return name as it is.
550 11 path := Absyn.Path.IDENT(name);
551 11 return;
552 else
553
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
36 if in_root_class and InstNode.isRootClass(cur_scope) then
554 // The scope was the root class, now we're start to look in the
555 // enclosing scopes of the root class.
556 in_root_class := false;
557 end if;
558
559 // Continue in the enclosing scope.
560 36 cur_scope := InstNode.parentScope(cur_scope);
561 end if;
562 end try;
563 end for;
564
565 ✗ fail();
566 end lookupSimpleNameRootPath;
567
568 function lookupNameWithError
569 input Absyn.Path name;
570 input InstNode scope;
571 input InstContext.Type context;
572 input SourceInfo info;
573 input ErrorTypes.Message errorType;
574 input Boolean checkAccessViolations = true;
575 output InstNode node;
576 output LookupState state;
577 output list<InstNode> prefixes;
578 algorithm
579 try
580 976112 (node, state, prefixes) := lookupName(name, scope, context, checkAccessViolations);
581 else
582 99 Error.addSourceMessage(errorType, {AbsynUtil.pathString(name), InstNode.scopeName(scope)}, info);
583 33 fail();
584 end try;
585 end lookupNameWithError;
586
587 function lookupName
588 input Absyn.Path name;
589 input InstNode scope;
590 input InstContext.Type context;
591 input Boolean checkAccessViolations;
592 output InstNode node;
593 output LookupState state;
594 output list<InstNode> prefixes
595 "The classes the name was looked up through, outermost first and excluding
596 the node itself, as found by the lookup and not as instPackage maps them.";
597 protected
598 Boolean self_reference;
599 InstNode prefix;
600 algorithm
601 (node, state, prefixes) := match name
602 // Simple name, look it up in the given scope.
603 case Absyn.Path.IDENT()
604 algorithm
605 450416 (node, state, _) := lookupFirstIdent(name.name, scope, context);
606 450408 then
607 (node, state, {});
608
609 // Qualified name, look up first part in the given scope and look up the
610 // rest of the name in the found element.
611 case Absyn.Path.QUALIFIED()
612 algorithm
613 525721 (prefix, state, self_reference) := lookupFirstIdent(name.name, scope, context);
614 525716 (node, state, prefixes) :=
615 lookupLocalName(name.path, prefix, state, context, checkAccessViolations, self_reference);
616 525696 then
617 (node, state, prefix :: prefixes);
618
619 // Fully qualified path, start from top scope.
620 case Absyn.Path.FULLYQUALIFIED()
621 1345 then lookupName(name.path, InstNode.topScope(scope), context, checkAccessViolations);
622
623 end match;
624 end lookupName;
625
626 function lookupNames
627 input Absyn.Path name;
628 input InstNode scope;
629 input InstContext.Type context;
630 output list<InstNode> nodes;
631 output LookupState state;
632 protected
633 Boolean self_reference;
634 algorithm
635 (nodes, state) := match name
636 local
637 InstNode node;
638
639 // Simple name, look it up in the given scope.
640 case Absyn.Path.IDENT()
641 algorithm
642 24633 (node, state) := lookupFirstIdent(name.name, scope, context);
643 24632 then
644 ({node}, state);
645
646 // Qualified name, look up first part in the given scope and look up the
647 // rest of the name in the found element.
648 case Absyn.Path.QUALIFIED()
649 algorithm
650 159164 (node, state, self_reference) := lookupFirstIdent(name.name, scope, context);
651 159164 then
652 lookupLocalNames(name.path, node, {node}, state, context, self_reference);
653
654 // Fully qualified path, start from top scope.
655 case Absyn.Path.FULLYQUALIFIED()
656 149 then lookupNames(name.path, InstNode.topScope(scope), context);
657
658 end match;
659 end lookupNames;
660
661 function lookupFirstIdent
662 "Looks up the first part of a name."
663 input String name;
664 input InstNode scope;
665 input InstContext.Type context;
666 output InstNode node;
667 output LookupState state;
668 output Boolean selfReference;
669 algorithm
670 try
671 // Check if the name refers to a reserved builtin name.
672 1159934 node := lookupSimpleBuiltinName(name);
673 state := LookupState.PREDEF_CLASS();
674 406894 selfReference := false;
675 else
676 // Otherwise, check each scope until the name is found.
677 753040 (node, selfReference) := lookupSimpleName(name, scope, context);
678 753026 state := LookupState.nodeState(node);
679 end try;
680 end lookupFirstIdent;
681
682 function lookupLocalName
683 "Looks up a path in the given scope, without continuing the search in any
684 enclosing scopes if the path isn't found."
685 input Absyn.Path name;
686 input output InstNode node;
687 input output LookupState state;
688 input InstContext.Type context;
689 input Boolean checkAccessViolations = true;
690 input Boolean selfReference = false;
691 output list<InstNode> prefixes = {} "See lookupName.";
692 protected
693 Boolean is_import;
694 InstNode prefix;
695 algorithm
696 // Looking something up in a component is only legal when the name begins with
697 // a component reference, and for that we use lookupCref. So if the given node
698 // is a component we can immediately quit and give an error.
699
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 721773 times.
721774 if not InstNode.isClass(node) then
700 1 state := LookupState.COMP_CLASS();
701 1 return;
702 end if;
703
704
2/2
✓ Branch 0 taken 650463 times.
✓ Branch 1 taken 71310 times.
721773 if not selfReference then
705 650463 node := Inst.instPackage(node, context);
706
707 // allow lookup in partial nodes if -d=nfAPI is on
708
6/6
✓ Branch 1 taken 285 times.
✓ Branch 2 taken 650177 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 282 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 2 times.
650462 if InstNode.isPartial(node) and not (InstContext.inRelaxed(context) or InstContext.inRedeclared(context)) then
709 1 state := LookupState.ERROR(LookupState.PARTIAL_CLASS());
710 1 return;
711 end if;
712 end if;
713
714 // Look up the path in the scope.
715 () := match name
716 case Absyn.Path.IDENT()
717 algorithm
718 525694 (node, is_import) := lookupLocalSimpleName(name.name, node);
719
720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 525694 times.
525694 if is_import then
721 ✗ state := LookupState.ERROR(LookupState.IMPORT());
722 else
723 525694 state := LookupState.next(node, state, context, checkAccessViolations);
724 end if;
725 then
726 ();
727
728 case Absyn.Path.QUALIFIED()
729 algorithm
730 196077 (prefix, is_import) := lookupLocalSimpleName(name.name, node);
731
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196058 times.
196058 if is_import then
733 node := prefix;
734 ✗ state := LookupState.ERROR(LookupState.IMPORT());
735 else
736 196058 state := LookupState.next(prefix, state, context, checkAccessViolations);
737 196058 (node, state, prefixes) := lookupLocalName(name.path, prefix, state, context, checkAccessViolations);
738 196040 prefixes := prefix :: prefixes;
739 end if;
740 then
741 ();
742
743 else
744 algorithm
745 ✗ Error.terminate(getInstanceName() + " was called with an invalid path.", sourceInfo());
746 ✗ then
747 fail();
748 end match;
749 end lookupLocalName;
750
751 function lookupLocalNames
752 "Looks up a path in the given scope, without continuing the search in any
753 enclosing scopes if the path isn't found."
754 input Absyn.Path name;
755 input InstNode scope;
756 input output list<InstNode> nodes;
757 input output LookupState state;
758 input InstContext.Type context;
759 input Boolean selfReference = false;
760 protected
761 InstNode node = scope;
762 algorithm
763 // Looking something up in a component is only legal when the name begins with
764 // a component reference, and for that we use lookupCref. So if the given node
765 // is a component we can immediately quit and give an error.
766
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 354878 times.
354879 if not InstNode.isClass(scope) then
767 state := LookupState.COMP_CLASS();
768 1 return;
769 end if;
770
771 // If the given node extends from itself, like 'extends Modelica.Icons.***' in
772 // the MSL, then it's already being instantiated here.
773
2/2
✓ Branch 0 taken 228115 times.
✓ Branch 1 taken 126763 times.
354878 if not selfReference then
774 228115 node := Inst.instPackage(node, context);
775
776 // PartialModelicaServices is mistakenly partial in MSL versions older than
777 // 3.2.3. We can't just check for Modelica 3.2 since that will break e.g. 3.2.2,
778 // so just disable the check specifically for PartialModelicaServices instead.
779
1/10
✗ Branch 1 not taken.
✓ Branch 2 taken 228113 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
228113 if InstNode.isPartial(node) and not (InstContext.inRelaxed(context) or InstContext.inRedeclared(context)) and
780 not InstNode.name(node) == "PartialModelicaServices" then
781 state := LookupState.ERROR(LookupState.PARTIAL_CLASS());
782 ✗ return;
783 end if;
784 end if;
785
786 // Look up the path in the scope.
787 (nodes, state) := match name
788 case Absyn.Path.IDENT()
789 algorithm
790 159161 node := lookupLocalSimpleName(name.name, node);
791 159161 state := LookupState.next(node, state, context);
792 then
793 (node :: nodes, state);
794
795 case Absyn.Path.QUALIFIED()
796 algorithm
797 195715 node := lookupLocalSimpleName(name.name, node);
798 195715 state := LookupState.next(node, state, context);
799 195715 then
800 lookupLocalNames(name.path, node, node :: nodes, state, context);
801
802 else
803 algorithm
804 ✗ Error.terminate(getInstanceName() + " was called with an invalid path.", sourceInfo());
805 ✗ then
806 fail();
807 end match;
808 end lookupLocalNames;
809
810 function lookupSimpleBuiltinName
811 input String name;
812 output InstNode builtin;
813 algorithm
814 builtin := match name
815 646186 case "Real" then NFBuiltin.REAL_NODE;
816 28930 case "Integer" then NFBuiltin.INTEGER_NODE;
817 62422 case "Boolean" then NFBuiltin.BOOLEAN_NODE;
818 77556 case "String" then NFBuiltin.STRING_NODE;
819 end match;
820 end lookupSimpleBuiltinName;
821
822 function lookupSimpleBuiltinCref
823 input String name;
824 input list<Absyn.Subscript> subs;
825 output InstNode node;
826 output ComponentRef cref;
827 output LookupState state;
828 algorithm
829 (node, cref, state) := match name
830 case "time"
831 10220 then (NFBuiltin.TIME, NFBuiltin.TIME_CREF, LookupState.PREDEF_COMP());
832 case "Boolean"
833 6 then (NFBuiltin.BOOLEAN_NODE, NFBuiltin.BOOLEAN_CREF, LookupState.PREDEF_CLASS());
834 case "Integer"
835 155 then (NFBuiltinFuncs.INTEGER_NODE, NFBuiltinFuncs.INTEGER_CREF, LookupState.FUNC());
836 case "String"
837 22460 then (NFBuiltinFuncs.STRING_NODE, NFBuiltinFuncs.STRING_CREF, LookupState.FUNC());
838 end match;
839
840
1/2
✓ Branch 0 taken 6569 times.
✗ Branch 1 not taken.
6569 if not listEmpty(subs) then
841 ✗ cref := ComponentRef.setSubscripts(list(Subscript.RAW_SUBSCRIPT(s) for s in subs), cref);
842 end if;
843 end lookupSimpleBuiltinCref;
844
845 function lookupSimpleCref
846 "This function look up a simple name as a cref in a given component."
847 input String name;
848 input list<Absyn.Subscript> subs;
849 input InstNode scope;
850 input InstContext.Type context;
851 output InstNode node;
852 output ComponentRef cref;
853 output InstNode foundScope = scope;
854 output Boolean inEnclosingScope = false;
855 output Boolean isIterator = false;
856 output LookupState state;
857 protected
858 Boolean require_builtin = false;
859 Boolean loaded = false;
860 algorithm
861 try
862 1288682 (node, cref, state) := lookupSimpleBuiltinCref(name, subs);
863 6569 foundScope := InstNode.topScope(foundScope);
864 else
865
2/2
✓ Branch 1 taken 1646 times.
✓ Branch 2 taken 1280467 times.
1282113 if InstContext.inAnnotation(context) then
866 // If in an annotation context, check the annotation environment first.
867 try
868 1646 (node, foundScope) := lookupLocalSimpleCref(name, InstNode.annotationScope(foundScope));
869 196 state := LookupState.nodeState(node);
870 196 cref := ComponentRef.fromAbsyn(node, subs);
871 196 return;
872 else
873 end try;
874 end if;
875
876 // Look for the name in the given scope, and if not found there continue
877 // through the enclosing scopes of that scope until we either run out of
878 // scopes or for some reason exceed the recursion depth limit.
879 520231 for i in 1:Global.recursionDepthLimit loop
880 try
881 1802148 (node, foundScope, isIterator) := lookupLocalSimpleCref(name, foundScope);
882
883
2/2
✓ Branch 0 taken 5667 times.
✓ Branch 1 taken 1276231 times.
1281898 if require_builtin then
884
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5667 times.
5667 true := InstNode.isBuiltin(node);
885 end if;
886
887 // We found a node, return it.
888 1281898 state := LookupState.nodeState(node);
889 1281898 cref := ComponentRef.fromAbsyn(node, subs, isIterator = isIterator);
890 1281898 return;
891 else
892 // Stop if the current scope is encapsulated.
893
2/2
✓ Branch 1 taken 5667 times.
✓ Branch 2 taken 514583 times.
520250 if InstNode.isEncapsulated(foundScope) then
894 5667 foundScope := InstNode.topScope(InstNode.parentScope(foundScope));
895 require_builtin := true;
896 else
897
4/4
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 514539 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 19 times.
514583 if InstNode.isTopScope(foundScope) and not loaded and not require_builtin then
898 // If the name couldn't be found in any scope, try to load a library
899 // with that name and then try to look it up in the top scope again.
900 25 loaded := true;
901 25 loadLibrary(name, foundScope);
902 else
903 // Look in the next enclosing scope.
904 514558 inEnclosingScope := not InstNode.isImplicit(foundScope);
905 514558 foundScope := InstNode.parentScope(foundScope);
906 end if;
907 end if;
908 end try;
909 end for;
910
911 ✗ Error.addMessage(Error.RECURSION_DEPTH_REACHED,
912 {String(Global.recursionDepthLimit), InstNode.scopeName(foundScope)});
913 ✗ fail();
914 end try;
915 end lookupSimpleCref;
916
917 function lookupLocalSimpleCref
918 "This function look up a simple name as a cref in a given component, without
919 searching in any enclosing scope."
920 input String name;
921 input InstNode scope;
922 output InstNode node;
923 output InstNode foundScope = scope;
924 output Boolean isIterator = false;
925 protected
926 Boolean is_import;
927 algorithm
928 (node, is_import) := match foundScope
929 case InstNode.IMPLICIT_SCOPE()
930 73821 then (lookupIterator(name, foundScope.locals), false);
931 case InstNode.CLASS_NODE()
932 1427245 then Class.lookupElement(name, InstNode.getClass(foundScope));
933 case InstNode.COMPONENT_NODE()
934 303843 then Class.lookupElement(name, InstNode.getClass(foundScope));
935 case InstNode.INNER_OUTER_NODE()
936 ✗ then Class.lookupElement(name, InstNode.getClass(foundScope.innerNode));
937 end match;
938
939
2/2
✓ Branch 0 taken 34166 times.
✓ Branch 1 taken 1249435 times.
1283601 if is_import then
940 34166 foundScope := InstNode.parent(node);
941 elseif InstNode.isInnerOuterNode(node) then
942 // If the node is an outer node, return the inner instead.
943 5206 node := InstNode.resolveInner(node);
944 5206 foundScope := InstNode.parent(node);
945 else
946 1244229 isIterator := InstNode.isIterator(node);
947 end if;
948 end lookupLocalSimpleCref;
949
950 function lookupIterator
951 input String name;
952 input list<InstNode> iterators;
953 output InstNode iterator;
954 algorithm
955
2/2
✓ Branch 0 taken 46512 times.
✓ Branch 1 taken 56428 times.
102940 for i in iterators loop
956
4/4
✓ Branch 1 taken 23303 times.
✓ Branch 2 taken 23209 times.
✓ Branch 5 taken 17393 times.
✓ Branch 6 taken 5910 times.
46512 if name == InstNode.name(i) then
957 iterator := i;
958 17393 return;
959 end if;
960 end for;
961
962 56428 fail();
963 end lookupIterator;
964
965 function lookupCrefInNode
966 input Absyn.ComponentRef cref;
967 input InstNode node;
968 input Boolean isIterator;
969 input output ComponentRef foundCref;
970 input output InstNode foundScope;
971 input output LookupState state;
972 input InstContext.Type context;
973 protected
974 InstNode scope;
975 InstNode n, cls_node;
976 String name;
977 Class cls;
978 Boolean is_import, scope_is_class;
979 algorithm
980
6/6
✓ Branch 1 taken 481947 times.
✓ Branch 2 taken 1 time.
✓ Branch 4 taken 19720 times.
✓ Branch 5 taken 462227 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 19719 times.
481948 if LookupState.isError(state) or (InstContext.inConnect(context) and InstNode.isEmpty(node)) then
981 2 return;
982 end if;
983
984 481946 scope := node;
985 481946 scope_is_class := InstNode.isClass(scope);
986
987
2/2
✓ Branch 0 taken 203098 times.
✓ Branch 1 taken 278848 times.
481946 if scope_is_class then
988 203098 scope := Inst.instPackage(node, context);
989
990
3/6
✓ Branch 1 taken 107 times.
✓ Branch 2 taken 202990 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 107 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
203097 if InstNode.isPartial(scope) and not (InstContext.inRelaxed(context) or InstContext.inRedeclared(context)) then
991 state := LookupState.ERROR(LookupState.PARTIAL_CLASS());
992 ✗ return;
993 end if;
994 elseif InstNode.isGeneratedInner(scope) and Component.isDefinition(InstNode.component(scope)) then
995 // The scope is a generated inner component that hasn't been instantiated,
996 // it needs to be instantiated to continue lookup.
997 ✗ Inst.instComponent(scope, NFAttributes.DEFAULT_ATTR, Modifier.NOMOD(), true, 0, NFInstContext.CLASS);
998 end if;
999
1000 481945 name := AbsynUtil.crefFirstIdent(cref);
1001 481945 cls_node := InstNode.classScope(scope);
1002
1003
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 481945 times.
481945 if InstNode.isEmpty(cls_node) then
1004 ✗ foundCref := ComponentRef.fromAbsynCref(cref, foundCref);
1005 ✗ return;
1006 end if;
1007
1008 481945 cls := InstNode.getClass(cls_node);
1009
1010 try
1011 481945 (n, is_import) := Class.lookupElement(name, cls);
1012 else
1013
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 58 times.
60 true := InstNode.isComponent(node);
1014
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
58 true := Class.isExpandableConnectorClass(cls) or InstContext.inInstanceAPI(context);
1015 58 foundCref := ComponentRef.fromAbsynCref(cref, foundCref);
1016 58 return;
1017 end try;
1018
1019
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 481884 times.
481885 if is_import then
1020 1 state := LookupState.ERROR(LookupState.IMPORT());
1021 1 foundCref := ComponentRef.fromAbsyn(n, {}, foundCref);
1022 1 return;
1023 end if;
1024
1025 481884 (n, foundCref, foundScope) := resolveInnerCref(n, foundCref, foundScope);
1026 481884 foundCref := ComponentRef.fromAbsyn(n, AbsynUtil.crefFirstSubs(cref), foundCref, isIterator = isIterator);
1027
1028
6/6
✓ Branch 0 taken 203094 times.
✓ Branch 1 taken 278790 times.
✓ Branch 3 taken 170728 times.
✓ Branch 4 taken 32366 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 170727 times.
481884 if scope_is_class and not InstContext.inRelaxed(context) and
1029 LookupState.isNonConstantComponent(n) then
1030 // An element found in a non-package must be encapsulated. So if we find a
1031 // non-constant component in a class it's an error, since packages may only
1032 // contain constant components and components can't be encapsulated.
1033 state := LookupState.ERROR(LookupState.NON_ENCAPSULATED());
1034 1 return;
1035 else
1036 481883 state := LookupState.next(n, state, context);
1037 end if;
1038
1039 (foundCref, foundScope, state) := match cref
1040 case Absyn.ComponentRef.CREF_IDENT() then (foundCref, foundScope, state);
1041
1042 case Absyn.ComponentRef.CREF_QUAL()
1043 86721 then lookupCrefInNode(cref.componentRef, n, isIterator, foundCref, foundScope, state, context);
1044 end match;
1045 end lookupCrefInNode;
1046
1047 function resolveInnerCref
1048 "If given an outer node, resolves it to the corresponding inner node and
1049 collapses the given cref so that it refers to the correct node. The scope a
1050 cref is found in may also change if the inner is outside the scope found by
1051 lookupCref."
1052 input output InstNode node;
1053 input output ComponentRef cref;
1054 input output InstNode foundScope;
1055 protected
1056 InstNode scope;
1057 algorithm
1058
2/2
✓ Branch 1 taken 481877 times.
✓ Branch 2 taken 7 times.
481884 if InstNode.isInnerOuterNode(node) then
1059 // Resolve the outer node to its inner.
1060 7 node := InstNode.resolveInner(node);
1061 7 scope := InstNode.parent(node);
1062
1063 // Removes parts of the cref until it's either empty or we find the parent of
1064 // the inner node. I.e. if we have a.b.c.d.e where e is outer and the inner e
1065 // is declared in b, then we remove d and c and stop at b to get a.b.e.
1066
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
18 while not ComponentRef.isEmpty(cref) loop
1067
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 4 times.
15 if referenceEq(ComponentRef.node(cref), scope) then
1068 break;
1069 else
1070 11 cref := ComponentRef.rest(cref);
1071 end if;
1072 end while;
1073
1074 // If the cref is now empty it means the inner was declared outside the
1075 // scope we found the first part of the cref in, so the found scope is
1076 // replaced with the scope of the inner.
1077
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 if ComponentRef.isEmpty(cref) then
1078 foundScope := scope;
1079 end if;
1080 end if;
1081 end resolveInnerCref;
1082
1083 function generateInner
1084 "Generates an inner element given an outer one, or returns the already
1085 generated inner element if one has already been generated."
1086 input InstNode outerNode;
1087 input InstNode topScope;
1088 output InstNode innerNode;
1089 protected
1090 InstNodeType node_ty;
1091 String name;
1092 Option<InstNode> inner_node_opt;
1093 algorithm
1094 153 node_ty := InstNode.nodeType(topScope);
1095
1096 () := match node_ty
1097 case InstNodeType.TOP_SCOPE()
1098 algorithm
1099 153 name := InstNode.name(outerNode);
1100 153 inner_node_opt := UnorderedMap.get(name, node_ty.generatedInners);
1101
1102
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 153 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 135 times.
153 if isSome(inner_node_opt) then
1103 // Found an already generated node, return it.
1104 135 SOME(innerNode) := inner_node_opt;
1105 else
1106 // Otherwise, generate a new inner node and add it to the cache.
1107 18 innerNode := makeInnerNode(outerNode);
1108 18 innerNode := InstNode.setNodeType(InstNodeType.GENERATED_INNER(), innerNode);
1109 18 UnorderedMap.add(name, innerNode, node_ty.generatedInners);
1110 end if;
1111 then
1112 ();
1113
1114 else
1115 algorithm
1116 ✗ Error.terminate(getInstanceName() + " got invalid top node", sourceInfo());
1117 ✗ then
1118 fail();
1119
1120 end match;
1121 end generateInner;
1122
1123 function makeInnerNode
1124 "Returns a copy of the given node where the element definition has been
1125 changed to have the inner prefix."
1126 input output InstNode node;
1127 algorithm
1128 node := match node
1129 local
1130 SCode.Element def;
1131 SCode.Prefixes prefs;
1132 Component comp;
1133
1134 case InstNode.CLASS_NODE(definition = def as SCode.CLASS(prefixes = prefs))
1135 algorithm
1136 1 prefs.innerOuter := Absyn.INNER();
1137 1 def.prefixes := prefs;
1138 1 node.definition := def;
1139 then
1140 node;
1141
1142 case InstNode.COMPONENT_NODE()
1143 algorithm
1144 17 comp := InstNode.component(node);
1145
1146 (comp, def) := match comp
1147 case Component.COMPONENT_DEF(definition = def as SCode.COMPONENT(prefixes = prefs))
1148 algorithm
1149 17 prefs.innerOuter := Absyn.INNER();
1150 17 def.prefixes := prefs;
1151 17 comp.definition := def;
1152 then
1153 (comp, def);
1154
1155 else
1156 algorithm
1157 ✗ Error.terminate(getInstanceName() + " got unknown component", sourceInfo());
1158 ✗ then
1159 fail();
1160 end match;
1161 17 then
1162 InstNode.replaceComponent(comp, InstNode.setDefinition(def, node));
1163
1164 else
1165 algorithm
1166 ✗ Error.terminate(getInstanceName() + " got unknown node", sourceInfo());
1167 ✗ then
1168 fail();
1169 end match;
1170 end makeInnerNode;
1171
1172 function loadLibrary
1173 "Tries to load the default version of a library and add it to the top scope."
1174 input String name;
1175 input InstNode scope;
1176 protected
1177 String version;
1178 algorithm
1179 403 ErrorExt.setCheckpoint(getInstanceName());
1180
1181 try
1182
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
403 true := Flags.getConfigBool(Flags.LOAD_MISSING_LIBRARIES);
1183 403 version := loadLibrary_work(name, scope);
1184 10 Error.addMessage(Error.NOTIFY_IMPLICIT_LOAD, {name, version});
1185 10 System.loadModelCallBack(name);
1186 10 ErrorExt.delCheckpoint(getInstanceName());
1187 else
1188 393 ErrorExt.rollBack(getInstanceName());
1189 end try;
1190 end loadLibrary;
1191
1192 function loadLibrary_work
1193 input String name;
1194 input InstNode scope;
1195 output String version = "(default)";
1196 protected
1197 String modelica_path;
1198 Absyn.Program aprog;
1199 SCode.Element scls;
1200 Class cls;
1201 InstNode lib_node;
1202 list<InstNode> new_libs = {};
1203 algorithm
1204 // Try to load the library.
1205 403 modelica_path := Settings.getModelicaPath(Testsuite.isRunning());
1206
2/2
✓ Branch 2 taken 393 times.
✓ Branch 3 taken 10 times.
403 (aprog, true) := BackendInterface.appendLibrary(Absyn.Path.IDENT(name), modelica_path);
1207
1208 // Multiple libraries might have been loaded due to uses-annotations.
1209 // Create nodes for the ones not yet defined in the top scope.
1210
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 10 times.
50 for c in aprog.classes loop
1211 try
1212 40 lookupLocalSimpleName(AbsynUtil.getClassName(c), scope);
1213 else
1214 27 scls := AbsynToSCode.translateClass(c);
1215 27 lib_node := InstNode.new(scls, scope);
1216 27 new_libs := lib_node :: new_libs;
1217
1218 // If this is the library we were looking for, try to find out which
1219 // version it is so we can tell the user.
1220
3/4
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 17 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
27 if name == SCodeUtil.getElementName(scls) then
1221 try
1222
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
10 SOME(Absyn.Exp.STRING(value = version)) :=
1223 SCodeUtil.lookupElementAnnotationBinding(scls, "version");
1224 else
1225 end try;
1226 end if;
1227 end try;
1228 end for;
1229
1230 // Append the new libraries to the scope.
1231 10 cls := InstNode.getClass(scope);
1232 10 cls := Class.classTreeApply(cls, function ClassTree.appendClasses(clsNodes = new_libs));
1233 10 InstNode.updateClass(cls, scope);
1234 end loadLibrary_work;
1235
1236 annotation(__OpenModelica_Interface="nf_frontend");
1237 end NFLookup;
1238