Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 83
Functions: -% 0 / 1 / 1
Branches: 0.0% 0 / 0 / 48

OMCompiler/Compiler/FFrontEnd/FLookup.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 FLookup
37 " file: FLookup.mo
38 package: FLookup
39 description: Scoping rules
40
41
42 "
43
44 public
45 import Absyn;
46 import AbsynUtil;
47 import FCore;
48 import FNode;
49
50 protected
51 import List;
52 import FGraph;
53 import FGraphBuild;
54
55 public
56 type Name = FCore.Name;
57 type Id = FCore.Id;
58 type Seq = FCore.Seq;
59 type Next = FCore.Next;
60 type Node = FCore.Node;
61 type Data = FCore.Data;
62 type Kind = FCore.Kind;
63 type Ref = FCore.Ref;
64 type Refs = FCore.Refs;
65 type Children = FCore.Children;
66 type Parents = FCore.Parents;
67 type ImportTable = FCore.ImportTable;
68 type Graph = FCore.Graph;
69 type Extra = FCore.Extra;
70 type Visited = FCore.Visited;
71 type Import = FCore.Import;
72 type Msg = Option<SourceInfo>;
73
74 constant Option<SourceInfo> dummyLookupOption = NONE(); // SOME(Absyn.dummyInfo);
75
76 public uniontype Options
77 record OPTIONS
78 Boolean ignoreImports;
79 Boolean ignoreExtends;
80 Boolean ignoreParents;
81 end OPTIONS;
82 end Options;
83
84 public constant Options ignoreNothing = OPTIONS(false, false, false);
85 public constant Options ignoreParents = OPTIONS(false, false, true);
86 public constant Options ignoreParentsAndImports = OPTIONS(true, false, true);
87 public constant Options ignoreAll = OPTIONS(true, true, true);
88
89 public function id
90 "@author: adrpo
91 search for id"
92 input Graph inGraph;
93 input Ref inRef;
94 input Name inName;
95 input Options inOptions;
96 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
97 output Graph outGraph;
98 output Ref outRef;
99 algorithm
100 (outGraph, outRef) := matchcontinue(inGraph, inOptions, inMsg)
101 local
102 Ref r;
103 Parents p;
104 Graph g;
105
106 // implicit scope which has for iterators
107 case (g, _, _)
108 algorithm
109 ✗ r := FNode.child(inRef, FNode.forNodeName);
110 ✗ r := FNode.child(r, inName);
111 ✗ then
112 (g, r);
113
114 /*/ self?
115 case (g, _, _, _, _)
116 algorithm
117 true = FNode.isRefImplicitScope(inRef);
118 true = stringEq(FNode.name(FNode.fromRef(inRef)), inName);
119 r = FNode.child(inRef, inName);
120 false = FNode.isRefImplicitScope(r);
121 then
122 (g, r);*/
123
124 // implicit scope? move upwards if allowed
125 case (g, OPTIONS(_, _, false), _)
126 algorithm
127 ✗ true := FNode.isRefImplicitScope(inRef);
128 // the original parent
129 ✗ r := FNode.refOriginalParent(inRef);
130 ✗ (g, r) := id(g, r, inName, inOptions, inMsg);
131 then
132 (g, r);
133
134 // local?
135 case (g, _, _)
136 algorithm
137 ✗ false := FNode.isRefImplicitScope(inRef);
138 ✗ r := FNode.child(inRef, inName);
139 ✗ then
140 (g, r);
141
142 // lookup in imports
143 case (g, OPTIONS(false, _, _), _)
144 algorithm
145 ✗ false := FNode.isRefImplicitScope(inRef);
146 ✗ (g, r) := imp(g, inRef, inName, inOptions, inMsg);
147 then
148 (g, r);
149
150 // lookup in extends
151 case (g, OPTIONS(_, false, _), _)
152 algorithm
153 ✗ false := FNode.isRefImplicitScope(inRef);
154 ✗ (g, r) := ext(g, inRef, inName, inOptions, inMsg);
155 then
156 (g, r);
157
158 // encapsulated
159 case (g, OPTIONS(_, _, false), _)
160 algorithm
161 ✗ false := FNode.isRefImplicitScope(inRef);
162 ✗ true := FNode.isEncapsulated(FNode.fromRef(inRef));
163 ✗ r := FNode.top(inRef);
164 ✗ (g, r) := id(g, r, inName, inOptions, inMsg);
165 then
166 (g, r);
167
168 // search parent
169 case (g, OPTIONS(_, _, false), _)
170 algorithm
171 ✗ false := FNode.isRefImplicitScope(inRef);
172 ✗ false := FNode.isEncapsulated(FNode.fromRef(inRef));
173 ✗ true := FNode.hasParents(FNode.fromRef(inRef));
174 // the original parent
175 ✗ r := FNode.refOriginalParent(inRef);
176 ✗ (g, r) := search(g, {r}, inName, inOptions, inMsg);
177 then
178 (g, r);
179
180 // top node reached
181 case (_, OPTIONS(_, _, false), _)
182 algorithm
183 ✗ false := FNode.hasParents(FNode.fromRef(inRef));
184 then
185 fail();
186
187 // failure
188 case (_, _, SOME(_))
189 algorithm
190 ✗ print("FLookup.id failed for: " + inName + " in: " + FNode.toPathStr(FNode.fromRef(inRef)) + "\n");
191 ✗ then
192 fail();
193
194 end matchcontinue;
195 end id;
196
197 public function search
198 "@author: adrpo
199 search for id in list"
200 input Graph inGraph;
201 input Refs inRefs;
202 input Name inName;
203 input Options inOptions;
204 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
205 output Graph outGraph;
206 output Ref outRef;
207 algorithm
208 (outGraph, outRef) := matchcontinue(inGraph, inRefs, inMsg)
209 local
210 Ref r;
211 Refs rest;
212 Graph g;
213
214 // not found
215 case (_, {}, _) then fail();
216
217 // found
218 case (g, r::_, _)
219 algorithm
220 ✗ (g, r) := id(g, r, inName, inOptions, inMsg);
221 then
222 (g, r);
223
224 // search rest
225 case (g, _::rest, _)
226 algorithm
227 ✗ (g, r) := search(g, rest, inName, inOptions, inMsg);
228 then
229 (g, r);
230
231 // failure
232 case (_, _, SOME(_))
233 algorithm
234 ✗ print("FLookup.search failed for: " + inName + " in: " +
235 FNode.toPathStr(FNode.fromRef(listHead(inRefs))) + "\n");
236 ✗ then
237 fail();
238
239 end matchcontinue;
240 end search;
241
242 public function name
243 "@author: adrpo
244 search for a name"
245 input Graph inGraph;
246 input Ref inRef;
247 input Absyn.Path inPath;
248 input Options inOptions;
249 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
250 output Graph outGraph;
251 output Ref outRef;
252 algorithm
253 (outGraph, outRef) := matchcontinue(inGraph, inPath, inMsg)
254 local
255 Ref r;
256 Name i;
257 Absyn.Path rest;
258 String s;
259 Graph g;
260
261 // simple name
262 case (g, Absyn.IDENT(i), _)
263 algorithm
264 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
265 then
266 (g, r);
267
268 // qualified name, could find the rest
269 case (g, Absyn.QUALIFIED(i, rest), _)
270 algorithm
271 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
272 ✗ (g, r) := name(g, r, rest, inOptions, inMsg);
273 then
274 (g, r);
275
276 // qualified name, could not find the rest, stop!
277 case (g, Absyn.QUALIFIED(i, rest), _)
278 algorithm
279 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
280 ✗ failure(name(g, r, rest, inOptions, inMsg));
281 // add an assersion node that it should
282 // be a name in here and return that
283 ✗ s := "missing: " + AbsynUtil.pathString(rest) + " in scope: " + FNode.toPathStr(FNode.fromRef(r));
284 // make the assert node have the name of the missing path part
285 ✗ (g, r) := FGraphBuild.mkAssertNode(AbsynUtil.pathFirstIdent(rest), s, r, g);
286 then
287 (g, r);
288
289 // fully qual name
290 case (g, Absyn.FULLYQUALIFIED(rest), _)
291 algorithm
292 ✗ r := FNode.top(inRef);
293 ✗ (g, r) := name(g, r, rest, inOptions, inMsg);
294 then
295 (g, r);
296
297 case (_, _, SOME(_))
298 algorithm
299 ✗ print("FLookup.name failed for: " + AbsynUtil.pathString(inPath) + " in: " + FNode.toPathStr(FNode.fromRef(inRef)) + "\n");
300 ✗ then
301 fail();
302
303 end matchcontinue;
304 end name;
305
306 public function ext
307 "@author: adrpo
308 search for id in extends"
309 input Graph inGraph;
310 input Ref inRef;
311 input Name inName;
312 input Options inOptions;
313 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
314 output Graph outGraph;
315 output Ref outRef;
316 algorithm
317 (outGraph, outRef) := matchcontinue inGraph
318 local
319 Ref r;
320 Refs refs;
321 Graph g;
322
323 // for class extends search inside the base class first
324 case g
325 algorithm
326 ✗ true := FNode.isClassExtends(FNode.fromRef(inRef));
327 // get its ref node
328 ✗ r := FNode.child(inRef, FNode.refNodeName);
329 // get the target from ref
330 ✗ r := FNode.target(FNode.fromRef(r));
331 // print("Searching for: " + inName + " in class extends target:\n\t" + FNode.toPathStr(FNode.fromRef(r)) + "\n");
332 // search in type target
333 ✗ (g, r) := id(g, r, inName, ignoreParents, inMsg);
334 // print("Found it in: " + FNode.toPathStr(FNode.fromRef(r)) + "\n");
335 then
336 (g, r);
337
338 // for class extends: if not found in base class search in the parents of this node
339 case g
340 algorithm
341 ✗ true := FNode.isClassExtends(FNode.fromRef(inRef));
342 // get the original parent
343 ✗ r := FNode.refOriginalParent(inRef);
344 ✗ (g, r) := id(g, r, inName, ignoreNothing, inMsg);
345 // print("Found it in: " + FNode.toPathStr(FNode.fromRef(r)) + "\n");
346 then
347 (g, r);
348
349 // get all extends of the node and search in them
350 case g
351 algorithm
352 ✗ refs := FNode.extendsRefs(inRef);
353 ✗ false := listEmpty(refs);
354 ✗ refs := List.mapMap(refs, FNode.fromRef, FNode.target);
355 // print("Searching for: " + inName + " in extends targets:\n\t" + stringDelimitList(List.mapMap(refs, FNode.fromRef, FNode.toPathStr), "\n\t") + "\n");
356 ✗ (g, r) := search(g, refs, inName, ignoreParentsAndImports, inMsg);
357 then
358 (g, r);
359
360 end matchcontinue;
361 end ext;
362
363 public function imp
364 "@author: adrpo
365 search for id in imports"
366 input Graph inGraph;
367 input Ref inRef;
368 input Name inName;
369 input Options inOptions;
370 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
371 output Graph outGraph;
372 output Ref outRef;
373 algorithm
374 (outGraph, outRef) := matchcontinue inGraph
375 local
376 Ref r;
377 list<Import> qi, uqi;
378 Graph g;
379
380 // lookup in qual
381 case g
382 algorithm
383 ✗ true := FNode.hasImports(FNode.fromRef(inRef));
384 ✗ (qi,_) := FNode.imports(FNode.fromRef(inRef));
385 ✗ (g, r) := imp_qual(g, inRef, inName, qi, inOptions, inMsg);
386 then
387 (g, r);
388
389 // lookup in un-qual
390 case g
391 algorithm
392 ✗ true := FNode.hasImports(FNode.fromRef(inRef));
393 ✗ (_, uqi) := FNode.imports(FNode.fromRef(inRef));
394 ✗ (g, r) := imp_unqual(g, inRef, inName, uqi, inOptions, inMsg);
395 then
396 (g, r);
397
398 end matchcontinue;
399 end imp;
400
401 protected function imp_qual
402 "Looks up a name through the qualified imports in a scope."
403 input Graph inGraph;
404 input Ref inRef;
405 input Name inName;
406 input list<Import> inImports;
407 input Options inOptions;
408 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
409 output Graph outGraph;
410 output Ref outRef;
411 algorithm
412 (outGraph, outRef) := matchcontinue(inGraph, inImports)
413 local
414 Name name;
415 Absyn.Path path;
416 list<Import> rest_imps;
417 Ref r;
418 Graph g;
419
420 // No match, search the rest of the list of imports.
421 case (g, Absyn.NAMED_IMPORT(name = name) :: rest_imps)
422 algorithm
423 ✗ false := stringEqual(inName, name);
424 ✗ (g, r) := imp_qual(g, inRef, inName, rest_imps, inOptions, inMsg);
425 then
426 (g, r);
427
428 // Match, look up the fully qualified import path.
429 case (g, Absyn.NAMED_IMPORT(name = name, path = path) :: _)
430 algorithm
431 ✗ true := stringEqual(inName, name);
432 ✗ (g, r) := fq(g, path, inOptions, inMsg);
433 then
434 (g, r);
435
436 // Partial match, return failure
437 case (_, Absyn.NAMED_IMPORT(name = name) :: _)
438 algorithm
439 ✗ true := stringEqual(inName, name);
440 then
441 fail(); // TODO! maybe add an assertion node!
442
443 end matchcontinue;
444 end imp_qual;
445
446 public function imp_unqual
447 "Looks up a name through the qualified imports in a scope. If it finds the
448 name it returns the item, path, and environment for the name, otherwise it
449 fails."
450 input Graph inGraph;
451 input Ref inRef;
452 input Name inName;
453 input list<Import> inImports;
454 input Options inOptions;
455 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
456 output Graph outGraph;
457 output Ref outRef;
458 algorithm
459 (outGraph, outRef) := matchcontinue(inGraph, inImports)
460 local
461 Absyn.Path path;
462 list<Import> rest_imps;
463 Ref r;
464 Graph g;
465
466 // For each unqualified import we have to look up the package the import
467 // points to, and then look among the public member of the package for the
468 // name we are looking for.
469 case (g, Absyn.UNQUAL_IMPORT(path = path) :: _)
470 algorithm
471 // Look up the import path.
472 ✗ (g, r) := fq(g, path, inOptions, inMsg);
473 // Look up the name among the public member of the found package.
474 ✗ (g, r) := id(g, r, inName, ignoreParents, inMsg);
475 then
476 (g, r);
477
478 // No match, continue with the rest of the imports.
479 case (g, _ :: rest_imps)
480 algorithm
481 ✗ (g, r) := imp_unqual(g, inRef, inName, rest_imps, inOptions, inMsg);
482 then
483 (g, r);
484 end matchcontinue;
485 end imp_unqual;
486
487 public function fq
488 "Looks up a fully qualified path in ref"
489 input Graph inGraph;
490 input Absyn.Path inName;
491 input Options inOptions;
492 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
493 output Graph outGraph;
494 output Ref outRef;
495 algorithm
496 ✗ (outGraph, outRef) := name(inGraph, FGraph.top(inGraph), inName, inOptions, inMsg);
497 end fq;
498
499 public function cr
500 "@author: adrpo
501 search for a component reference"
502 input Graph inGraph;
503 input Ref inRef;
504 input Absyn.ComponentRef inCref;
505 input Options inOptions;
506 input Msg inMsg "Message flag, SOME() outputs lookup error messages";
507 output Graph outGraph;
508 output Ref outRef;
509 algorithm
510 (outGraph, outRef) := matchcontinue(inGraph, inCref, inMsg)
511 local
512 Ref r;
513 Name i;
514 Absyn.ComponentRef rest;
515 Graph g;
516 String s;
517
518 // simple name
519 case (g, Absyn.CREF_IDENT(i, _), _)
520 algorithm
521 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
522 then
523 (g, r);
524
525 // qualified name, first is component
526 case (g, Absyn.CREF_QUAL(i, _, rest), _)
527 algorithm
528 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
529 // inRef is a component, lookup in type
530 ✗ true := FNode.isRefComponent(r);
531 // get the ref
532 ✗ r := FNode.child(r, FNode.refNodeName);
533 // get the target from ref
534 ✗ r := FNode.target(FNode.fromRef(r));
535 // search in type target
536 ✗ (g, r) := cr(g, r, rest, ignoreParents, inMsg);
537 then
538 (g, r);
539
540 // qualified name
541 case (g, Absyn.CREF_QUAL(i, _, rest), _)
542 algorithm
543 // inRef is a class
544 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
545 ✗ true := FNode.isRefClass(r);
546 ✗ (g, r) := cr(g, r, rest, ignoreParents, inMsg);
547 then
548 (g, r);
549
550 // qualified name
551 case (g, Absyn.CREF_QUAL(i, _, rest), _)
552 algorithm
553 // inRef is a class
554 ✗ (g, r) := id(g, inRef, i, inOptions, inMsg);
555 ✗ true := FNode.isRefClass(r) or FNode.isRefComponent(r);
556 // add an assersion node that it should
557 // be a name in here and return that
558 ✗ s := "missing: " + AbsynUtil.crefString(rest) + " in scope: " + FNode.toPathStr(FNode.fromRef(r));
559 // make the assert node have the name of the missing cref part
560 ✗ (g, r) := FGraphBuild.mkAssertNode(AbsynUtil.crefFirstIdent(rest), s, r, g);
561 then
562 (g, r);
563
564
565 // fully qual name
566 case (g, Absyn.CREF_FULLYQUALIFIED(rest), _)
567 algorithm
568 ✗ r := FGraph.top(g);
569 ✗ (g, r) := cr(g, r, rest, inOptions, inMsg);
570 then
571 (g, r);
572
573 case (_, _, SOME(_))
574 algorithm
575 ✗ print("FLookup.cr failed for: " + AbsynUtil.crefString(inCref) + " in: " + FNode.toPathStr(FNode.fromRef(inRef)) + "\n");
576 ✗ then
577 fail();
578
579 end matchcontinue;
580 end cr;
581
582 annotation(__OpenModelica_Interface="frontend");
583 end FLookup;
584